|
cout.setf(ios::fixed); //以定點形式顯示浮點數
cout.precision(4); //設置小數部分的4位有效數字
設序列X={x1,x2,x3......xm}和Y={y1,y2,y3,....yn},要求最長公共子序列,可以按照下面方式遞歸計算,:當xm=yn時,找出Xm-1和Yn-1的最長公共子序列,然后在其尾部加上xm即可得到X和Y的最長公共子序列,當xm不等于yn的時候,必須解決兩個子問題即找出Xm-1和Y的最長公共子序列和Yn-1和X的最長工公共子序列,然后這兩個里面較長者為X和Y的最長公共子序列! 首先建立子問題的最優值遞歸關系。用C[i][j]表示Xi和Yj的最長公共子序列的長度。其中,Xi={x1,x2,x3......xi},Yj={y1,y2,y3,....yn},當i=0或者j=0時空序列是Xi和Yj的最長公共子序列,故因此,C[i][j]=0,即有 代碼如下: C[i][j]=0,(i=0,j=0) C[i][j]=c[i-1][j-1]+1,xi=yj C[i][j]=max(C[i][j-1],C[i-1][j]),i,j>0,xi不等于yj述
最長公共子串(Longest common substring, 簡稱LCS)問題指的是求出給定的一組 字符串的長度最大的共有的子字符串。 舉例說明,以下三個字符串的LCS就是 cde: abcde cdef ccde
現在的情況是給你2個字符串,請找到他們的LCS
請注意:字符可以不相鄰;
輸入
輸入第一行包含一個整數T,表示有T組數據;
對于每組數據包含2行,每行包含一個非空字符串,長度不超過1000個字符
輸出
對于每組數據輸出他們的LCS的長度,保證每組數據存在LCS;
樣例輸入
2 abcde cdef aaaaaaa aaabaaa
樣例輸出 3 6
分析:
設序列X={x1,x2,x3......xm}和Y={y1,y2,y3,....yn},要求最長公共子序列,可以按照下面方式遞歸計算,:當xm=yn時,找出Xm-1和Yn-1的最長公共子序列,然后在其尾部加上xm即可得到X和Y的最長公共子序列,當xm不等于yn的時候,必須解決兩個子問題即找出Xm-1和Y的最長公共子序列和Yn-1和X的最長工公共子序列,然后這兩個里面較長者為X和Y的最長公共子序列! 首先建立子問題的最優值遞歸關系。用C[i][j]表示Xi和Yj的最長公共子序列的長度。其中,Xi={x1,x2,x3......xi},Yj={y1,y2,y3,....yn},當i=0或者j=0時空序列是Xi和Yj的最長公共子序列,故因此,C[i][j]=0,即有 C[i][j]=0,(i=0,j=0) C[i][j]=c[i-1][j-1]+1,xi=yj C[i][j]=max(C[i][j-1],C[i-1][j]),i,j>0,xi不等于yj 實現代碼如下: #include<stdio.h> #include<string.h> int c[1002][1002]={0}; int main() { int N,m,n,i,j; char x[1002],y[1002]; scanf("%d",&N); while(N--) { scanf("%s",x); scanf("%s",y); m=strlen(x); n=strlen(y); for(i=1;i<=m;i++) for(j=1;j<=n;j++) { if(x[i-1]==y[j-1]) { c[i][j]=c[i-1][j-1]+1; } else if(c[i-1][j]>=c[i][j-1]) { c[i][j]=c[i-1][j]; } else { c[i][j]=c[i][j-1]; } } printf("%d\n",c[m][n]); } return 0; } 參考自: http://yangchuanhuahpu.blog.163.com/blog/static/18631884020125272205862/
轉。 // %.*s 其中的.*表示顯示的精度 對字符串輸出(s)類型來說就是寬度 // 這個*代表的值由后面的參數列表中的整數型(int)值給出
// 例如: printf("%.*s\n", 1, "abc"); // 輸出a printf("%.*s\n", 2, "abc"); // 輸出ab printf("%.*s\n", 3, "abc"); // 輸出abc >3是一樣的效果 因為輸出類型type = s,遇到'\0'會結束
描述 對于一個字符串S1,其中S2是他的一個子串(長度嚴格小于S1長度),如果S2在S1中出現次數超過1次,那么S2就是一個重復子串,現在的要求是給定S1,請求出他的最長重復子串;
如果有多個長度一樣的最長子串,請輸入字典序最小那個串;
比如bbbaaaccc
那么最長子串就是aa
輸入 第一行包含一個整數T,表示有T組數據
對于每組數據包含一行,該行有一個字符串,長度小于10,000
輸出 對于每組數據請輸出他的最長重復子串,保證每組數據都有;
樣例輸入 2 abacabac abacabbac
樣例輸出 abac bac
代碼測試通過(普通版):
#include<stdio.h> #include<string.h> #define N 10000 int main() { char a[N]; int i,j,n,t,p,max,t1; scanf("%d",&t1); while(t1--) { max = 0; scanf("%s",a); n=strlen(a); for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { t=0; while(a[i+t]==a[j+t]&&(j+t)<n) t++; if(t>max) { max=t; p=i; } else if(t == max) //如果有長度一樣的最長重復子串,那么比較它們的字典序 { if(a[i]<a[p]) { max = t; p = i; } } } } for(i=p;i<p+max;i++) printf("%c",a[i]); printf("\n"); } return 0; } 普通算法效率較低,為O(n²)。 第二種方法是用后綴數組實現。轉自:http://hi.baidu.com/qwertlooker/item/44f3fe52ad772cdbd58bacfd
如果程序至多可以處理MAXN個字符,這些字符被存儲在數組c中: #define MAXN 5000000 char c[MAXN], *a[MAXN]; 在讀取輸入時,首先初始化a,這樣,每個元素就都指向輸入字符串中的相應字符: while (ch = getchar()) != EOF a[n] = &c[n]; c[n++] = ch; c[n] = 0 //將數組c中的最后一個元素設為空字符,以終止所有字符串 這樣,元素a[0]指向整個字符串,下一個元素指向以第二個字符開始的數組的后綴,等等。如若輸入字符串為"banana",該數組將表示這些后綴: a[0]:banana a[1]:anana a[2]:nana a[3]:ana a[4]:na a[5]:a 由于數組a中的指針分別指向字符串中的每個后綴,所以將數組a命名為"后綴數組"
第二,對后綴數組進行快速排序,以將后綴相近的(變位詞)子串集中在一起 qsort(a, n, sizeof(char*), pstrcmp)后 a[0]:a a[1]:ana a[2]:anana a[3]:banana a[4]:na a[5]:nana
第三,使用以下comlen函數對數組進行掃描比較鄰接元素,以找出最長重復的字符串: for i = [0, n) if comlen(a[i], a[i+1]) > maxlen maxlen = comlen(a[i], a[i+1]) maxi = i printf("%.*s\n", maxlen, a[maxi]) 由于少了內層循環,只是多了一次排序,因此該算法的運行時間為O(n logn). (nlogn比n大,取nlogn) 實現代碼如下: #include <stdio.h> #include <stdlib.h> #include <string.h>
#define MAXCHAR 10000 //最長處理10000個字符
char c[MAXCHAR], *a[MAXCHAR];
int comlen( char *p, char *q ){ //計算最長重復子串的長度 int i = 0; while( *p && (*p++ == *q++) ) ++i; return i; }
int pstrcmp( const void *p1, const void *p2 ){ return strcmp( *(char* const *)p1, *(char* const*)p2 ); }
int main( ){ int t; char ch; int i, temp; scanf("%d\n",&t); while(t--) { int n=0; int maxlen=0, maxi=0;
while( (ch=getchar())!='\n' ){ a[n]=&c[n]; c[n++]=ch; } c[n]='\0'; qsort( a, n, sizeof(char*), pstrcmp ); //快速排序對后綴數組進行排序,以使后綴相同的子串集中在一起, //以便接下來comlen函數對這些子串進行計算其最長重復子串 for(i=0; i<n-1; ++i ){ temp=comlen( a[i], a[i+1] ); if( temp>maxlen ) { maxlen=temp; maxi=i; } } printf("%.*s\n",maxlen, a[maxi]); //輸出最長重復子串 } return 0; }
第三種方法似乎可以用后綴樹實現,效率可以提高到O(n),具體的后綴樹講解可以參照這篇文章: http://blog.csdn.net/v_july_v/article/details/6897097(PS:智商有限,后面部分講解理解不了)
歸并排序法是將兩個(或兩個以上)有序表合并成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然后再把有序子序列合并為整體有序序列。 例如,有數列{6,202,100,301,38,8,1} 1. 剛開始的分組如下: i=1 [6 202 ] [ 100 301] [ 8 38] [ 1 ] 比較次數為3次 2. 第二次,兩兩分組合并 i=2 [ 6 100 202 301 ] [ 1 8 38 ] 比較次數為4 3. 第三次,繼續合并 i=3 [ 1 6 8 38 100 202 301 ] 比較次數為4 總計的比較次數為11次 歸并排序具體工作原理如下(假設序列共有n個元素): 1. 將序列每相鄰兩個數字進行歸并操作,形成floor(n / 2)個序列,排序后每個序列包含兩個元素 2. 將上述序列再次歸并,形成floor(n / 4)個序列,每個序列包含四個元素 3. 重復步驟2,直到所有元素排序完畢 歸并操作的過程如下: 1. 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合并后的序列 2. 設定兩個指針,最初位置分別為兩個已經排序序列的起始位置 3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合并空間,并移動指針到下一位置 4. 重復步驟3直到某一指針達到序列尾 5. 將另一序列剩下的所有元素直接復制到合并序列尾 自底向上歸并,如圖所示:  遞歸實現代碼: #include <iostream> using namespace std; void merge(int*arr, int p, int q, int r) { int n1 = q - p + 1; int n2 = r - q; int* L = new int[n1]; int* R = new int[n2]; for(int i = 0; i < n1; i++) { L[i] = arr[p + i]; } for(int j = 0; j < n2; j++) { R[j] = arr[q + j + 1]; } int i = 0; int j = 0; int k = p; while((i < n1) && (j < n2)) { if(L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } if (i < n1) { for(; i < n1; i++, k++) { arr[k] = L[i]; } } if (j < n2) { for(; j < n2; j++, k++) { arr[k] = R[j]; } } } void mergesort(int* arr, int p, int r) { int q = 0; if(p < r) { q = (p + r) / 2; mergesort(arr, p, q); mergesort(arr, q + 1, r); merge(arr, p, q, r); } } int main() { int a[] = {5, 2, 4, 7, 1, 3, 2, 6}; mergesort(a, 0, 7); for(int i = 0; i < 8; i++) { cout << a[i] << " "; } cout << endl; return 0; } 非遞歸代碼實現: /** * merge_sort: 非遞歸實現 --迭代 * 非遞歸思想: 將數組中的相鄰元素兩兩配對。用merge函數將他們排序, * 構成n/2組長度為2的排序好的子數組段,然后再將他們排序成長度為4的子數組段, * 如此繼續下去,直至整個數組排好序。 **/ #include <stdio.h> #include <stdlib.h> // merge_sort(): 非遞歸實現-自底向上 // 將原數組劃分為left[min max] 和 right[min max]兩部分 void merge_sort( int *list, int length) { int i, left_min, left_max, right_min, right_max, next; int *tmp = ( int*)malloc( sizeof( int) * length); if (tmp == NULL) { fputs("Error: out of memory\n", stderr); abort(); } for (i = 1; i < length; i *= 2) // i為步長,1,2,4,8……
{ for (left_min = 0; left_min < length - i; left_min = right_max) { right_min = left_max = left_min + i; //right_min取left_max的值,以下要用到left_max的值才不會改變left_max原先值
right_max = left_max + i; if (right_max > length) //如果right_max超出了數組長度,則right_max等于數組長度
right_max = length; next = 0; while (left_min < left_max && right_min < right_max) //tmp[next]存儲子數組中的最小值
tmp[next++] = list[left_min] > list[right_min] ? list[right_min++] : list[left_min++]; while (left_min < left_max) //如果left_min小于left_max,則將最小值原封不動地賦給list[--right_min],right_min 要先減1
list[--right_min] = list[--left_max]; while (next > 0) //將tmp[next]存儲的最小值放入list[--right_min]中
list[--right_min] = tmp[--next]; } if(i == 1) //打印第一次歸并后的數字排列
{ for( int j=0;j<length;j++) printf("%d ",list[j]); printf("\n"); } } free(tmp); } int main() { int a[1000],t,i; scanf("%d",&t); for(i=0;i<t;i++) { scanf("%d",&a[i]); } merge_sort(a, t); // print array for (i = 0; i < t; i++) printf("%d ", a[i]); return 0; }
動態規劃解決01背包問題! 代碼
#include<stdio.h> int c[10][100];/*對應每種情況的最大價值*/int w[10],p[10];int knapsack(int m,int n){ int i,j,x[10]; //w為物品重量,p為價值 for(i=1;i<n+1;i++) scanf("\n%d%d",&w[i],&p[i]); for(i=0;i<10;i++) for(j=0;j<100;j++) c[i][j]=0;/*初始化數組*/ for(i=1;i<n+1;i++) for(j=1;j<m+1;j++) { if(w[i]<=j) /*如果當前物品的重量小于背包所能承載的重量*/ { if(p[i]+c[i-1][j-w[i]]>c[i-1][j]) /*如果本物品的價值加上背包剩下的空間能放的物品的價值*/ /*大于上一次選擇的最佳方案則更新c[i][j]*/ c[i][j]=p[i]+c[i-1][j-w[i]]; else c[i][j]=c[i-1][j]; } else c[i][j]=c[i-1][j]; } printf("\n"); int contain = m; for(int i=n;i>0;--i) { if(c[i][contain] == c[i-1][contain])//未放入第i個物品,contain表示當前背包的承受重量 x[i-1] = 0; //考慮:f[i][j] = max{ f[i-1][j] 和 f[i-1][j - w[i]] + v[i] }, if ( f[i][j] == f[i-1][j] ) else //則說明物品i未放入;否則物品i 放入了背包中,最大承重量也相應減去w[i] { x[i-1] = 1; contain -= w[i]; // 放上了第i個物品,當前背包的重量要減去相應的物品i的重量,回溯 } } for(i=0;i<n;i++) { printf("%d ",x[i]); //1表示放入,0表示未放入 } printf("\n"); return(c[n][m]);}int main() { int m,n,i,j; scanf("%d %d",&m,&n); printf("Input the weight and value:\n"); printf("%d\n",knapsack(m,n)); return 0;}//測試數據:5 4 //2 12 //1 10 //3 20 //2 15 //結果:1 1 0 1 最大價值:37
給定一顆二叉樹的邏輯結構如下圖,(先序遍歷的結果,空樹用字符‘0’表示,例如AB0C00D00),建立該二叉樹的二叉鏈式存儲結構。
編寫程序輸出該樹的所有葉子結點和它們的父親結點
Input
第一行輸入一個整數t,表示有t個二叉樹
第二行起,按照題目表示的輸入方法,輸入每個二叉樹的先序遍歷,連續輸入t行
Output
第一行按先序遍歷,輸出第1個示例的葉子節點
第二行輸出第1個示例中與葉子相對應的父親節點
以此類推輸出其它示例的結果
Sample Input
3 AB0C00D00 AB00C00 ABCD0000EF000 Sample Output
C D B A B C A A D F C E
代碼:
#include <iostream> using namespace std;
class BiTreeNode
{
private:
BiTreeNode *leftChild; //左子樹指針
BiTreeNode *rightChild; //右子樹指針
public:
char data; //數據域 char father;
//構造函數和析構函數
BiTreeNode():leftChild(NULL), rightChild(NULL){}
BiTreeNode(char item, char father, BiTreeNode *left = NULL,
BiTreeNode *right = NULL):
data(item), father(father), leftChild(left), rightChild(right){}
~BiTreeNode(){}
BiTreeNode * &Left(void) //注意返回值類型為指針的引用類型
{return leftChild;}
BiTreeNode * &Right(void) //注意返回值類型為指針的引用類型
{return rightChild;} };
class BiTree
{
private:
BiTreeNode *root; //根結點指針
int i;
void Destroy(BiTreeNode * &t); void PreLeave(BiTreeNode * &t);
void Prefather(BiTreeNode * &t);
void CreateBiTree(BiTreeNode * &T,const char strTree[],char father);
public:
//構造函數和析構函數
BiTree(void):root(NULL),i(0){}; //構造函數
~BiTree(void){}; //析構函數
//構造二叉樹
void MakeTree(const char item,char father, BiTree &left, BiTree &right); //構造二叉樹
void MakeTree(const char strTree[]); //構造二叉樹,利用先序遍歷結果建樹
void Destroy(void); //銷毀二叉樹
void PreLeave(); //前序遍歷 void Prefather();
};
//2、定義銷毀函數
void BiTree ::Destroy(void) //銷毀二叉樹,公有函數
{
Destroy(root);
}
void BiTree ::Destroy(BiTreeNode * &t)
//銷毀二叉樹,私有函數供共有函數調用
{
if(t != NULL && t->Left() != NULL)
Destroy(t->Left());
if(t != NULL && t->Right() != NULL)
Destroy(t->Right());
if(t != NULL)
{
// cout << t->data << " "; //此語句只是為了方便測試
delete t;
}
}
//3、定義建樹函數
void BiTree::MakeTree(const char item, char father,BiTree &left, BiTree &right)
//構造數據域為item,左子樹為left,右子樹為right的二叉樹
{
root = new BiTreeNode(item,father, left.root, right.root);
}
void BiTree::MakeTree(const char strTree[])
//構造二叉樹,利用先序遍歷結果建樹,公有函數
{
i=0; char rootfather = '0'; CreateBiTree(root,strTree,rootfather);
}
void BiTree::CreateBiTree(BiTreeNode * &T, const char strTree[],char father) //遞歸建樹私有函數
{
char ch;
ch=strTree[i++];
if (ch=='0') T = NULL;
else
{
T=new BiTreeNode();
T->data = ch; // 生成根結點 T->father = father; father = ch;
CreateBiTree(T->Left(), strTree,father); // 構造左子樹
CreateBiTree(T->Right(), strTree,father); // 構造右子樹
}
}
//4、定義先序遍歷函數
void BiTree::PreLeave()
//前序遍歷訪問二叉樹,公有函數
{
PreLeave(root);
}
void BiTree::PreLeave(BiTreeNode* &t)
//前序遍歷訪問二叉樹,私有函數t
{
if(t)//若二叉樹結點不為空,執行如下操作: { if(!t->Left() && !t->Right()) //如果當前結點是葉子 cout<<t->data<<" "; PreLeave(t->Left());//2、先序遍歷該結點的左孩子
PreLeave(t->Right());//3、先序遍歷該結點的右孩子 }
}
//5、定義遍歷父節點函數
void BiTree::Prefather()
{
Prefather(root);
}
void BiTree:: Prefather(BiTreeNode* &t)
//中序遍歷訪問二叉樹,私有函數t
{
if(t)//若二叉樹結點不為空,執行如下操作: { if(!t->Left() && !t->Right())//如果當前結點是葉子,輸出它的父親 cout<<t->father<<" "; Prefather(t->Left()); Prefather(t->Right());
}
}
int main(void)
{
int n,i;
char strTree[800];
BiTree myTree;
cin>>n;
cin.get();
for(i=0;i<n;i++)
{
cin>>strTree;
myTree.MakeTree(strTree);
myTree.PreLeave();
cout<<endl;
myTree.Prefather();
cout<<endl;
myTree.Destroy();
}
return 0;
}
二叉樹可以采用數組的方法進行存儲,把數組中的數據依次自上而下,自左至右存儲到二叉樹結點中,一般二叉樹與完全二叉樹對比,比完全二叉樹缺少的結點就在數組中用0來表示
結點存儲的數據均為非負整數
Input
第一行輸入一個整數t,表示有t個二叉樹
第二行起,每行輸入一個數組,先輸入數組長度,再輸入數組內數據,每個數據之間用空格隔開,輸入的數據都是非負整數
連續輸入t行
Output
每行輸出一個示例的先序遍歷結果,每個結點之間用空格隔開
Sample Input
3 3 1 2 3 5 1 2 3 0 4 13 1 2 3 4 0 5 6 7 8 0 0 9 10 Sample Output
1 2 3 1 2 4 3 1 2 4 7 8 3 5 9 10 6
分析:這道題的關鍵在于:設定數組位置從1開始編號,那么位置為i的結點,它的左孩子在數組的位置是2i,右孩子在數組的位置是2i+1
這道題的難點在把樹建立起來,其他都容易。
代碼:
#include <iostream> using namespace std;
class BiTreeNode {
private:
BiTreeNode *leftChild; //左子樹指針
BiTreeNode *rightChild; //右子樹指針
public:
int data; //數據域
//構造函數和析構函數
BiTreeNode():leftChild(NULL), rightChild(NULL){}
BiTreeNode(int item, BiTreeNode *left = NULL,
BiTreeNode *right = NULL):
data(item), leftChild(left), rightChild(right){}
~BiTreeNode(){}
BiTreeNode * &Left(void) //注意返回值類型為指針的引用類型
{return leftChild;}
BiTreeNode * &Right(void) //注意返回值類型為指針的引用類型
{return rightChild;}
};
class BiTree
{
private:
BiTreeNode *root; //根結點指針
int i,len; //len是樹結點的數量
void Destroy(BiTreeNode * &t);
void PreOrder(BiTreeNode * &t);
void CreateBiTree(BiTreeNode * &T,const int arrTree[],int pos);
public:
//構造函數和析構函數
BiTree(void):root(NULL),i(0){}; //構造函數
~BiTree(void){}; //析構函數
//構造二叉樹
void MakeTree(const int arrTree[],int num); //構造二叉樹,利用先序遍歷結果建樹
void Destroy(void); //銷毀二叉樹
void PreOrder(); //前序遍歷
};
//2、定義銷毀函數
void BiTree ::Destroy(void) //銷毀二叉樹,公有函數
{
Destroy(root);
}
void BiTree ::Destroy(BiTreeNode * &t)
//銷毀二叉樹,私有函數供共有函數調用
{
if(t != NULL && t->Left() != NULL)
Destroy(t->Left());
if(t != NULL && t->Right() != NULL)
Destroy(t->Right());
if(t != NULL)
{ delete t; }
}
//3、定義建樹函數
void BiTree::MakeTree(const int arrTree[],int num)
//構造二叉樹,利用先序遍歷結果建樹,公有函數
{
i=0; len = num;
CreateBiTree(root,arrTree,1);//數組位置從1開始
}
void BiTree::CreateBiTree(BiTreeNode * &T, const int arrTree[],int pos) //遞歸建樹私有函數
{
int ch;
ch=arrTree[pos];
if (ch == 0 || pos > len) T = NULL;
else
{
T=new BiTreeNode();
T->data = ch; // 生成根結點 i++; if(i>len) return;
CreateBiTree(T->Left(), arrTree,2*pos); // 構造左子樹
CreateBiTree(T->Right(), arrTree,2*pos+1); // 構造右子樹
}
}
//4、定義先序遍歷函數
void BiTree::PreOrder()
//前序遍歷訪問二叉樹,公有函數
{
PreOrder(root);
}
void BiTree::PreOrder(BiTreeNode* &t)
//前序遍歷訪問二叉樹,私有函數t
{
if(t!=NULL)//若二叉樹結點不為空,執行如下操作: { cout<<t->data<<" ";//1、輸出當前結點的數據,表示該結點被訪問了
PreOrder(t->Left());//2、先序遍歷該結點的左孩子
PreOrder(t->Right());//3、先序遍歷該結點的右孩子 }
}
int main() { int m,i,j,k; int *arrTree; BiTree myTree; cin>>m; for(i=0;i<m;i++) { arrTree = new int[800]; cin>>k; for(j=1;j<=k;j++) cin>>arrTree[j]; myTree.MakeTree(arrTree,k); myTree.PreOrder(); cout<<endl; delete []arrTree; myTree.Destroy(); } return 0; }
描述 給一些包含加減號和小括號的表達式,求出該表達式的值。表達式中的數值均為絕對值小于 10 的整數。
輸入 第一行為表達式的個數 n,以下 n 行每行有一個表達式。每個表達式的長度不超過 20 個字符。
輸出 對每個表達式,輸出它的值。
樣例輸入 3 3-(2+3) -9+8+(2+3)-(-1+4) 0-0 樣例輸出 -2 1 0
//對每種情況都要考慮清楚
#include <cctype> #include <iostream> #include <string> #include <stack> #include <map>
using namespace std;
int getPrecedence(const char optr) //給各個操作符定義優先級順序,利用map容器 { map<char, int> precedTable; precedTable['#'] = 0; precedTable[')'] = 1; precedTable['+'] = 2; precedTable['-'] = 2; precedTable['*'] = 3; precedTable['/'] = 3; precedTable['('] = 10; return precedTable[optr]; }
int calculate(int a, char optr, int b) { switch (optr) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } }
int evaluate(const string& expr) { stack<int> opnd; stack<char> optr; char last_ch = '\0'; //每次檢查字符時的前一個字符 for (size_t i = 0; i != expr.size(); ++i) { const char ch = expr[i]; if (isspace(ch)) { //如果是空格,即跳過 continue; } else if (isdigit(ch)) { //如果是數字,則壓入操作數棧 opnd.push(ch - '0'); } else { if ((ch == '-' || ch == '+') && (last_ch == '\0' || last_ch == '(')) //遇到 '+'、'-',則壓入0進操作數棧 opnd.push(0); //如 7-1,遇'-'則壓入0進棧,,'-'則進操作符棧,遇到下一個數1,計算0-1得-1 if (optr.empty() || ch == '(' || (optr.top() == '(' && ch != ')') || getPrecedence(ch) > getPrecedence(optr.top())) { optr.push(ch); } else { while (!optr.empty() && optr.top() != '(' && getPrecedence(ch) <= getPrecedence(optr.top())) { int b = opnd.top(); opnd.pop(); int a = opnd.top(); opnd.pop(); opnd.push(calculate(a, optr.top(), b)); optr.pop(); } if (ch == ')') optr.pop(); else optr.push(ch); } } last_ch = ch; } while (!optr.empty()) { int b = opnd.top(); opnd.pop(); int a = opnd.top(); opnd.pop(); opnd.push(calculate(a, optr.top(), b)); optr.pop(); } int result = opnd.top(); opnd.pop(); return result; }
int main() { int n; cin >> n; while (n-- > 0) { string expr; cin>>expr; cout << evaluate(expr) << endl; } return 0; }
#include<iostream> #include<string> using namespace std; char a[100]; int i; int eval() { int x=0; while(a[i] == ' ') i++; if(a[i] == '+') { i++; return eval()+eval(); } if(a[i] == '*') { i++; return eval()*eval(); } while((a[i] >= '0')&&(a[i]<= '9')) x = 10*x +a[i++]-'0'; return x; } int main() { gets(a); cout<< eval()<<endl; return 0; }
|