1. 程式人生 > 其它 >資料結構學習(二)棧

資料結構學習(二)棧

出棧順序:由大變小按順序,由小變大可突變

  • C++指標特性測試

    #include <iostream>
    using namespace std;
    int main(){
        int *p=new int[10];
        for(int i=0;i<10;i++){
            p[i]=0;
        }
        int k=0;
        *p++=2;     //(*p)++=2會報錯
        cout<<p[-1]<<" "<<p[0]<<endl;	//p++後基指標後移一位,下標前移一位
        p--;    //不做p--delete會出問題
        delete [] p;   
        return 0;
    }
    

    *p++=2相當於先 *p=2p++ ,注意不是 (*p)++ 的效果,這是因為C++中 ++ 的優先順序高於 * ,先 p++*p ,由於 p++ 先返回 p ,所以會出現以上效果。

    (*p)++=2 會報錯,左側使用了 ++ 運算子,已不是一個可賦值的左值。

ADT

const int MAXLISTSIZE = 100;
template<class ElemType>
class SqStack{
   private:
      ElemType *base;   // 棧底指標
      ElemType *top;   // 棧頂指標
      int maxSize;        // 允許的最大儲存容量(以sizeof(ElemType)為單位
   public:
      //初始化順序棧
      SqStack(int ms = MAXLISTSIZE):maxSize(ms){
          top=new ElemType[ms];
          base=top;
      };
      //刪除順序棧
      ~SqStack(){StackDestroy();}
      //將順序棧置為空表
      bool StackClear(){
          if(top==base) return 0;	//健壯性設定
          top=base;
          return 1;
      };
      //返回順序棧的長度
      int StackLength() const {return top - base;}
      //設定順序棧的長度,不怎麼實用
      //bool SetListLength(int len);
      //判斷順序棧是否為空棧
      bool StackisEmpty() const{ return top == base; }
      //判斷順序棧是否為滿棧
      bool StackFull() const{
          return top-base==maxSize;
      };
      //用e返回棧頂元素
      bool GetTop(ElemType &e) const{   //通過傳入形參獲取值,返回值標記是否獲取成功
          if(top==base) return 0;
          e=*(top-1);
          return 1;
      };
      //入棧
      bool push(ElemType e){
          if(top-base>=maxSize) return 0;
          *top++=e;	//效果相當於先*top賦值,再top加一
          return 1; 
      };
      //出棧
      bool pop(ElemType &e){
          if(top==base) return 0;
          e=*--top;
          return 1;
      };
      //銷燬順序棧
      bool StackDestroy(){
          if(!base)
            return 0;
          delete[] base;	//起初是沒加[],用於基礎資料型別時沒有區別,但用於物件型別就有區別了。
          top=base=NULL;
          return 1;
      };
      //遍歷順序棧
      void StackTraverse() const{
          ElemType *p=top;
          while(p!=base){   //以此為判斷標準則p必須模擬棧頂指標
              cout<<*(p-1); //棧頂值在指標下面
              p--;  //別忘了迭代
          }
          return;
      };
      //棧空間加倍
      bool DoubleSpace(){ maxSize=2*maxSize;return 1; };
      ElemType getElem(int n) const{ return *(base+n); }    //從棧底到棧頂按下標獲取元素
};

函式(使用ADT)

逆置輸出

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

// ADT..

template<class ElemType>
void Invert_Input( SqStack<ElemType> &S ){
    string str;
    getline(cin,str);
    int k=str.length();
    for(int i=0;i<k;i++){
        S.push(str[i]);
    }
    return ;
};

int main(){
    SqStack<char> stc;
    Invert_Input(stc);
    stc.StackTraverse();
    return 0;
}

進位制轉換

輸入十進位制非負數與進位制數,輸出轉換後的結果,字母為大寫

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// ADT
/*
bool push(ElemType &e){	<!-1
          if(top-base>=maxSize) return 0;
          *top++=e;
          return 1; 
      };
*/
template<class ElemType>
void Conversion(SqStack<ElemType> &S, int data, int format){
    while(data){
        int k=data%format;
        char c[2]={char(55+k),char(48+k)};	//<!-1
        if(k>=10) S.push(c[0]);
        else S.push(c[1]);
        data/=format;	//別忘了迭代!
    }
    return ;
};
int main(){
    int a,b;
    cin>>a>>b;
    SqStack<char> stc;
    Conversion<char>(stc,a,b);
    stc.StackTraverse();
    return 0;
}
  • <!-1 此處若將push函式中的形參採取引用形式,則在傳入引數時不能直接傳入值,只能傳入相應變數,否則會出現報錯:

    cannot bind non-const lvalue reference of type 'char&' to an rvalue of type 'char'
    

    顯然這裡push函式可以不帶引號,因此問題不大。

括弧匹配檢驗

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
//ADT
template<class ElemType>
bool Matching( SqStack<ElemType> &S ){
    string str;
    getline(cin,str);
    int k=str.length();
    for(int i=0;i<k;i++){
        switch(str[i]){
            case '(':{
                S.push(str[i]);
                break;
            }
            case ')':{
                char c;
                S.GetTop(c);	//<!-1
                  //  cout<<" c="<<c;
                if(c=='('){
                    S.pop(c);
                } else return 0;
                break;
            }
            case '[':{
                S.push(str[i]);
                break;
            }
            case ']':{
                char c;
                S.GetTop(c);
                if(c=='['){ //檢測是否閉合
                    S.pop(c);   //閉合了則取出
                } else return 0;    //不閉合則必定出錯
            }
        }
    }
    if(S.StackisEmpty()) return 1;  //棧中無多餘括號
    else return 0;
};
int main(){
    SqStack<char> stc;
    if(Matching(stc)) cout<<"Correct";
    else cout<<"Wrong";
    return 0;
}
  • <!-1 不必加上判定 if(S.GetTop(c)) 再執行內部語句,因為當棧內本就為空時會返回false,而此時仍可能出現括號不匹配的情況,也就是無論執行是否成功都要判斷。事實上,如果加上了卻沒意識到這點,可能會導致找不出BUG。

中綴式轉換字尾式

一開始想的很麻煩,打算給數字入兩次棧反轉順序,後來發現這樣不僅麻煩還處理不了符號,所以就去搜了搜,發現思路不是這樣的,其實很簡單,碰到數字就輸出,判斷符號優先順序,符合要求就輸出符號即可,這裡我用矩陣表示符號優先順序問題:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0};  //operatorPriority
//運算子順序:'+','-','*','/','(',')','#' 1表示大於,0等於,-1小於,2非法
/*
  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =

注意這是運算子與其後運算子的優先順序比較
*/
bool isoperator( char op){ //運算子辨識
    switch(op){
        case '+':return 1;
        case '-':return 1;
        case '*':return 1;
        case '/':return 1;
        case '(':return 1;
        case ')':return 1;
        case '#':return 1;
        default:return 0;
    }
}
int op2Int(char c){ //運算子轉對應矩陣編號,-1表示異常
    if(!isoperator(c)) return -1;
    switch(c){
        case '+':return 0;
        case '-':return 1;
        case '*':return 2;
        case '/':return 3;
        case '(':return 4;
        case ')':return 5;
        case '#':return 6;
    }
    return -1;
}
template<class ElemType>
void infix_to_suffix( SqStack<ElemType> &S, string &infix, string &suffix){
    string number;
    S.push('#');    //忘了push導致讀取不到
    infix=infix+'#';
    int k=infix.length();   //放在+'#'之後!
    for(int i=0;i<k;i++){
        if(isoperator(infix[i])){
          //  cout<<"!! ";
            if(number!=""){
                if(suffix!="") suffix=suffix+" ";   //規範格式
                suffix=suffix+number;  //直接輸出數字,注意是suffix+string
              //  cout<<suffix<<endl;
                number="";
            }
            while(1){
                char c;
                S.GetTop(c); //獲取棧頂元素
                int k2=op2Int(infix[i]),k1=op2Int(c);
                // cout<<infix[i]<<":"<<k2<<" "<<c<<":"<<k1<<" "<<opp[k1][k2]<<endl;
                if(opp[k1][k2]==1){
                    S.pop(c);
                    if(suffix!="") suffix=suffix+" ";
                    suffix=suffix+c;
                } else
                    if(opp[k1][k2]==0){ //界限符相抵
                        S.pop(c);
                        break;
                    } else {
                        S.push(infix[i]);
                        break;
                    }
            }
        } else {
            number=number+infix[i];
        }
    }

};
int main(){
    string str,sufstr;
    SqStack<char> tmp;   //存運算子
    getline(cin,str);
    infix_to_suffix(tmp,str,sufstr);
    cout<<sufstr;
    return 0;
}

寫的時候犯了蠻多錯,比如 suffix=suffix+number 漏掉suffix自己,初始沒有將'#'入棧,+'#' 之前就取了infix的長度。格式化因為有suffix的存在,可以直接檢測是否為空來判斷前置空格。

string2Int

本題沒用上,留個檔:

int string2Int(string s){   //string轉int
    int n=0,k=s.length();
    for(int i=0;i<k;i++){
        n=n*10+int(s[i]-48);
    }
    return n;
}

參考:[

sisterryaya-字尾表示式轉中綴表示式

]

利用字尾式計算中綴式

輸入一串中綴式,輸出字尾式以及計算結果,運算元為int,結果為double:

const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0};  //operatorPriority
//運算子順序:'+','-','*','/','(',')','#' 1表示大於,0等於,-1小於,2非法
/*
  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =

注意這是運算子與其後運算子的優先順序比較
*/

int string2Int(string s){   //string轉int
    int n=0,k=s.length();
    for(int i=0;i<k;i++){
        n=n*10+int(s[i]-48);
    }
    return n;
}
bool isoperator( char op){  //運算子辨識
    switch(op){
        case '+':return 1;
        case '-':return 1;
        case '*':return 1;
        case '/':return 1;
        case '(':return 1;
        case ')':return 1;
        case '#':return 1;
        default:return 0;
    }
}
double opCalc(double a,double b,char c){ //計算
    if(!isoperator(c)) return 0;    //非法運算子返回0
    switch(c){
        case '+':{
            return a+b;
        }
        case '-':{
            return a-b;
        }
        case '*':{
            return a*b;
        }
        case '/':{
            return a/b;
        }
    }
    return 0;
}
int op2Int(char c){ //運算子轉對應矩陣編號,-1表示異常
    if(!isoperator(c)) return -1;
    switch(c){
        case '+':return 0;
        case '-':return 1;
        case '*':return 2;
        case '/':return 3;
        case '(':return 4;
        case ')':return 5;
        case '#':return 6;
    }
    return -1;
}
template<class ElemType>
double calc_suffix( SqStack<ElemType> &S, string &suffix ){
    SqStack<char> optr; //儲存運算子
    string str;
    getline(cin,str);   //輸入中綴式
    str=str+" #";	//只設計在空格讀取數字,所以需要新增空格
    optr.push('#');
    int k=str.length(); //中綴式長度
    string number;  //提取數字
    for(int i=0;i<k;i++){
        if(isoperator(str[i])){
            int k1,k2=op2Int(str[i]);
            while(1){
                char c;
                optr.GetTop(c);
                k1=op2Int(c);
                // cout<<"c="<<c<<endl;
                if(opp[k1][k2]==1){
                    optr.pop(c);
                    if(suffix!="") suffix=suffix+" ";   //規範輸出空格
                    suffix=suffix+c;	//儲存中綴表示式
                    double a,b;
                    S.pop(a);
                    S.pop(b);   //b在前a在後
                    b=opCalc(b,a,c);
                    S.push(b);
                } else 
                    if(opp[k1][k2]==0){
                        optr.pop(c);
                        break;
                    } else {
                        optr.push(str[i]);	//推入的是遍歷的內容! <!-1
                        break;
                    }
            }
        } else
            if(str[i]==' '){	//題目中輸入的中綴式以空格分開,所以用空格標記數字的讀取
                if(number!=""){
                    S.push(string2Int(number));
                    if(suffix!="") suffix=suffix+" ";
                    suffix=suffix+number;
                    number="";
                }
            }
            else number=number+str[i];
    }
    double tmp;
    S.pop(tmp);
    return tmp;
};
int main(){
    string suf;
    SqStack<double> opnd;   //存中間量
    double tmp=calc_suffix(opnd,suf);
    cout<<suf<<endl<<endl;
    cout<<tmp;
    return 0;
}
  • <!-1 犯錯兩次,每次都推入棧頂符號導致BUG出現..

火車排程

這題不難,但是讓我發現了一個指標動態陣列的問題:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
/*ADT
//建構函式
SqStack(int ms = MAXLISTSIZE):maxSize(ms){
          top=new ElemType[ms];
          base=top;
        //   cout<<"base:"<<base<<endl;
      };
//出棧
bool pop(ElemType &e){
          if(top==base) return 0;
          e=*--top;
        //   cout<<"&e="<<&e<<endl;
          return 1;
      };
//銷燬順序棧
      bool StackDestroy(){
          if(!base)
            return 0;
        //   cout<<*(base+1)<<" base:"<<base;
          delete []base;    //?加個[]就行了?	<!-1
          top=base=NULL;
          return 1;
      };
*/
template<class ElemType>
string Conversion(SqStack<ElemType> &S, string &train){
    stringstream ss(train);
    string tmp,ord;
    while(ss>>tmp){
        if(tmp[0]=='H'){
            S.push(tmp);
        } else {
            if(ord!="") ord=ord+" ";
            ord=ord+tmp;
        }
    }
    // cout<<"how much:"<<S.StackLength()<<endl;
    while(!S.StackisEmpty()){
        S.pop(tmp);
        if(ord!="") ord=ord+" ";
        ord=ord+tmp;
    }
    return ord;
};
int main(){
    string tr,res;
    getline(cin,tr);
    SqStack<string> stc(40);
    res=Conversion(stc,tr);
    cout<<res<<" ";
    // cout<<endl<<stc.StackisEmpty()<<endl<<sizeof(string)<<endl;
    return 0;
}

  • string的大小:32位元組(大的離譜,我一直以為是不規則的大小)
  • <!-1 這個地方delete不加 [] 會一直報錯"Unkonwn Signal",起初以為是指標指向出了問題,輸出指標地址後發現一切正常,但它就是報錯。後來發現是 delete base 語句的問題,早該想到這裡是陣列,必須要加上[],所以之前一直犯了這個錯,但奇怪的是隻有使用string的時候暴露了這個問題,所以我去了解了一下有無[]的區別,得出的結論是有[]用於陣列,無[]用於非陣列,[]的存在會呼叫陣列部分所有的解構函式,而無[]只會呼叫首個的解構函式。

參考:[

知乎-C++"Unkonwn Signal"報錯原因

]

迷宮問題

矩形迷宮尋路問題:

//ADT
const int dir[4][2]={0,1,1,0,0,-1,-1,0};    //東南西北順序

struct node{
    int x;
    int y;
    int ord;
    node(){};    //自行構建建構函式後預設建構函式不作數
    node(int a,int b,int c):x(a),y(b),ord(c){};
};


//遍歷輸出
void Traverse(SqStack<node> const &S){
    int k=S.StackLength();
    for(int i=0;i<k;i++){
        if(i) cout<<"->";
        if(i && !(i%4)) cout<<endl;
        node tmp=S.getElem(i);
        cout<<"("<<tmp.x-1<<","<<tmp.y-1<<")";
    }
    return;
};

bool InputMaze(int row, int col, vector< vector<int> > &maze){  //別忘了陣列的引用!
    for(int i=1;i<=row;i++){
        for(int j=1;j<=col;j++){
            cin>>maze[i][j];
        }
    }
    return 1;
}

template<class ElemType>
void maze_path( SqStack<ElemType> &S, int row, int col, node enter, node outer, vector< vector<int> > maze ){
    int x=enter.x+1, y=enter.y+1, ord=-1;   //入口座標需要處理
    // cout<<x<<","<<y;
    maze[x][y]=1;
    bool f=1;
    int i;
    while(f){
        // cout<<"1:"<<x<<","<<y<<endl;
        // cin>>x; //手動斷點
        for(i=ord+1;i<4;i++){
            int xx=x+dir[i][0],yy=y+dir[i][1];	//逐一遍歷方向
            // cout<<"2:"<<xx<<","<<yy<<"="<<maze[xx][yy]<<endl;
            // cin>>x;
            if(!maze[xx][yy]){
                node nd(x,y,i);
                S.push(nd);
                maze[xx][yy]=2;	//遍歷過的結點標記為2,此處深搜不做回退
                x=xx;
                y=yy;
                ord=-1;  //進入新的結點,ord置-1
                // cout<<"3:"<<x<<","<<y<<endl;
                // cin>>x;
                break;
            }
        }
        if(x==outer.x+1 && y==outer.y+1){	//找到出口
            S.push(node(x,y,ord));	//推入最後一個結點
            break;
        }
        if(x==enter.x+1 && y==enter.y+1) f=0;   //如果起點終點同一點,則語句順序很重要
        if(i==4){
            node tmp;
            S.pop(tmp);
            x=tmp.x;
            y=tmp.y;
            ord=tmp.ord;
            // cout<<"4:"<<x<<","<<y<<endl;
            // cin>>x;
        }
    }
    if(f){  //找到出口
        Traverse(S);
    } else {
        cout<<"No Path";
    }

    return ;
}

int main(){
    SqStack<node> stc;
    int row,col;
    cin>>row>>col;
    vector< vector<int> > maze(row+2,vector<int>(col+2,1));
    node beg,end;
    cin>>beg.x>>beg.y;
    cin>>end.x>>end.y;
    InputMaze(row,col,maze);
    // for(int i=0;i<=row+1;i++){   //檢查輸入是否成功
    //     for(int j=0;j<=col+1;j++){
    //         cout<<maze[i][j]<<" ";
    //     }
    //     cout<<endl;
    // }
    maze_path(stc,row,col,beg,end,maze);
    return 0;
}

總結一下:
先說犯的錯誤,一是輸入用函式打包,但傳入引數時未引用導致輸入失敗;二是ord在進入新的結點時未置-1導致方向遍歷不完全,這裡若是合理調整了退出語句與處理語句的順序本來可以較容易看出來的。
再說說收穫,我發現手動斷點可以用輸入語句替代,中間量輸出標記與值,達到一個良好的除錯效果。

迴文判斷

判斷一串以&為分隔符,以@為結束符的字串是否為迴文:

template<class ElemType>
bool parlindrome_judge( SqStack<ElemType> &S ){
    string s;
    char c;
    getline(cin,s,'@');   //規定@為結束符並排除
    int i=0,k=s.length();
    while(s[i]!='&'){
        S.push(s[i]);
        i++;
    }
    i++;
    if(k-i!=i-1) return 0;
    else {
        for(;i<k;i++){
            S.pop(c);
            if(c!=s[i]) return 0;
        }
    }
    return 1;
}
int main(){
    SqStack<char> stc;
    if(parlindrome_judge(stc)) cout<<"true";
    else cout<<"false";
    return 0;
}

中字尾轉換四則運算

跟之前的不同之處在於可以忽略輸入中的空格並把處理後的中綴式與結果輸出:

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

//ADT

const int opp[7][7]={1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,1,1,1,-1,1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,0,2,1,1,1,1,2,1,1,-1,-1,-1,-1,-1,2,0};  //operatorPriority
//運算子順序:'+','-','*','/','(',')','#' 1表示大於,0等於,-1小於,2非法
/*
  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = x
) > > > > x > >
# < < < < < x =

注意這是運算子與其後運算子的優先順序比較
*/

int string2Int(string s){   //string轉int
    int n=0,k=s.length();
    for(int i=0;i<k;i++){
        n=n*10+int(s[i]-48);
    }
    return n;
}
bool isoperator( char op){  //運算子辨識
    switch(op){
        case '+':return 1;
        case '-':return 1;
        case '*':return 1;
        case '/':return 1;
        case '(':return 1;
        case ')':return 1;
        case '#':return 1;
        default:return 0;
    }
}
double opCalc(double a,double b,char c){ //計算
    if(!isoperator(c)) return 0;    //非法運算子返回0
    switch(c){
        case '+':{
            return a+b;
        }
        case '-':{
            return a-b;
        }
        case '*':{
            return a*b;
        }
        case '/':{
            return a/b;
        }
    }
    return 0;
}
int op2Int(char c){ //運算子轉對應矩陣編號,-1表示異常
    if(!isoperator(c)) return -1;
    switch(c){
        case '+':return 0;
        case '-':return 1;
        case '*':return 2;
        case '/':return 3;
        case '(':return 4;
        case ')':return 5;
        case '#':return 6;
    }
    return -1;
}
template<class ElemType>
double calc_inffix( SqStack<ElemType> &S, string &inffix ){
    SqStack<char> optr; //儲存運算子
    string str;
    getline(cin,str);   //輸入中綴式
    str=str+"#";
    optr.push('#');
    int k=str.length(); //中綴式長度
    string number;  //提取數字
    for(int i=0;i<k;i++){
        if(isoperator(str[i])){
            if(str[i]!='#')
                inffix=inffix+str[i];
            if(number!=""){
                S.push(string2Int(number));
                number="";
            }
            int k1,k2=op2Int(str[i]);
            while(1){
                char c;
                optr.GetTop(c);
                k1=op2Int(c);
                // cout<<"c="<<c<<endl;
                if(opp[k1][k2]==1){
                    optr.pop(c);
                    double a,b;
                    S.pop(a);
                    S.pop(b);   //b在前a在後
                    b=opCalc(b,a,c);
                    S.push(b);
                } else 
                    if(opp[k1][k2]==0){
                        optr.pop(c);
                        break;
                    } else {
                        optr.push(str[i]);
                        break;
                    }
            }
        } else
            if(str[i]==' ') continue;
            else {
                number=number+str[i];
                inffix=inffix+str[i];
            }
    }
    double tmp;
    S.pop(tmp);
    return tmp;
};
int main(){
    string suf;
    SqStack<double> opnd;   //存中間量
    double tmp=calc_inffix(opnd,suf);
    cout<<suf<<endl<<endl;
    cout<<tmp;
    return 0;
}

奇怪的鍵盤

給一個字串,進行遞迴的消消樂,兩兩相同一起消除:

//遍歷輸出
void Traverse(SqStack<char> const &S){
    int k=S.StackLength();
    for(int i=0;i<k;i++){
        cout<<S.getElem(i);
    }
    return;
};

template<class ElemType>
void noTheSame( SqStack<ElemType> &S ){
    string str;
    getline(cin,str);
    int k=str.length();
    for(int i=0;i<k;i++){
        if(!i) S.push(str[i]);
        else{
            char c;
            S.GetTop(c);
            if(c!=str[i]) S.push(str[i]);   //別老是push你那c啊喂!
            else S.pop(c);
        }
        // Traverse(S);
        // cout<<endl;
    }
    return;
}
int main(){
    SqStack<char> stc;
    noTheSame(stc);
    Traverse(stc);
    return 0;
}

每次都push(c),每次都De這個BUG,不長記性了屬於是。

函式(遞迴)

求最大值

簡單的求序列最大值:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

int findMax(int n){
    int k;
    cin>>k;
    if(n==1) return k;
    else{
        int t=findMax(n-1);
        return k>t?k:t;
    }
}

int main(){
    int n;
    cin>>n;
    cout<<findMax(n);
    return 0;
}

中點優先的順序遍歷順序表

先遍歷一遍順序表,再取中點,先輸出中點,再輸出左半段,再輸出右半段;每段的輸出規則都同上:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

void midOut(int l,int r,vector<int> v){
    if(l>r) return;	//左端點小於右端點則退出
    int m=(l+r)/2;	
    cout<<v[m]<<" ";	//先輸出中點
    midOut(l,m-1,v);	//先左半部分,右端點為m-1
    midOut(m+1,r,v);	//再右半部分,左端點為m+1
    return;
}

int main(){
    int n;
    cin>>n;
    vector<int> v(n);
    for(int i=0;i<n;i++){
        cin>>v[i];
    }
    for(int i=0;i<n;i++){
        cout<<v[i]<<" ";	//先遍歷一遍
    }
    cout<<endl;
    midOut(0,n-1,v);
    return 0;
}

函式(使用STL)

stack 定義在標頭檔案 <stack> 中,基本用法:

e=stack.top();	//返回棧頂元素
stack.empty();	//判斷堆疊是否為空
e=stack.size();	//返回堆疊的大小
stack.pop();	//去除棧頂元素
stack.push(e)	//將元素e推入棧
stack <int> s;	//建立棧物件

棒球比賽

題目:

輸入分數或特定記號'C','D','+',處理分數最終得到總分

示例:

輸入:5 2 C D +

輸出:30

解釋:

"5" - 記錄加 5 ,記錄現在是 [5]

"2" - 記錄加 2 ,記錄現在是 [5, 2]

"C" - 使前一次得分的記錄無效並將其移除,記錄現在是 [5].

"D" - 記錄加 2 * 5 = 10 ,記錄現在是 [5, 10].

"+" - 記錄加 5 + 10 = 15 ,記錄現在是 [5, 10, 15].

所有得分的總和 5 + 10 + 15 = 30

程式碼:

#include <iostream>
#include <string>
#include <stack>
#include <sstream>
#include <vector>
using namespace std;

int string2Int(string s){   //string轉int,可分辨正負
    int f=1;
    if(s[0]=='-'){
        f=-1;
        s.erase(0,1); //去掉負號
    }
    int n=0,k=s.length();
    for(int i=0;i<k;i++){
        n=n*10+int(s[i]-48);
    }
    return n*f;
}

int calPoints(string s){
    stack<int> sta;
    stringstream ss(s);
    int cnt=0;
    while(ss>>s){
        int k=s.length();
        if(s[0]>='0' && s[0]<='9' || s[0]=='-'){  //如果一位數字
            int tmp=string2Int(s);
            sta.push(tmp);
        } else {    //其他記號
            switch(s[0]){
                case 'C':{
                    sta.pop();
                    break;
                }
                case 'D':{
                    int tmp=sta.top();
                    sta.push(tmp*2);
                    break;
                }
                case '+':{
                    int t=sta.top(),t1; //取出棧頂元素
                    sta.pop();
                    t1=sta.top();   //取出原棧頂下的元素
                    t1=t1+t;
                    sta.push(t);    //推入原棧頂
                    sta.push(t1);   //推入新棧頂
                }
            }
        }
    }
    while(!sta.empty()){    //計算棧內總值
        int k=sta.top();
        sta.pop();
        cnt+=k;
    }
    return cnt;
}

int main(){
    string s;
    getline(cin,s);
    cout<<calPoints(s);
    return 0;
}

比較含退格的字串

給定兩個字串,其中'#'表示退格,比較退格後的兩串是否相等,要求時間複雜度為O(n):

#include <iostream>
#include <string>
#include <stack>
#include <sstream>
#include <vector>
using namespace std;

bool backTheSame(string S,string T){
    stack<char> s1,s2;
    int k1=S.length(),k2=T.length();
    for(int i=0;i<k1;i++){
        if(S[i]=='#' && !s1.empty()) s1.pop(); //退格處理,注意空棧不可pop
        else s1.push(S[i]);
    }
    for(int i=0;i<k2;i++){
        if(T[i]=='#' && !s2.empty()) s2.pop();
        else s2.push(T[i]);
    }
    if(s1.size()!=s2.size()){	//比較長度
        cout<<s1.size()<<" "<<s2.size();
        // cout<<"?";
        return 0;
    }
    else{
        while(!s1.empty()){	//逐一比較
            char c1,c2;
            c1=s1.top();
            c2=s2.top();
            s1.pop();
            s2.pop();
            if(c1!=c2){
                // cout<<"!";
                return 0;
            }
        }
    }
    return 1;
}

int main(){
    string s,t;
    getline(cin,s);
    getline(cin,t);
    bool f=backTheSame(s,t);
    if(f) cout<<"true";
    else cout<<"false";
    return 0;
}