日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

邓俊辉数据结构学习-3-栈

發布時間:2025/7/25 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 邓俊辉数据结构学习-3-栈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

棧的學習

棧的應用場合

  • 逆序輸出
    • 輸出次序與處理過程顛倒,遞歸深度和輸出長度不易預知
    • 不是很理解
    • 實例:進制轉換
    • 大致思路:對于進制轉換,我們一般使用的都是長除法,因此要保存每次得到的余數,但是最后算下來
      新的進制的數,剛好和存儲的時候是逆序的。因此利用棧輸出即可。原因是棧是FiLo后進先出。
  • 遞歸嵌套
    • 具有自相似性的問題可遞歸描述,但分支位置和嵌套深度不固定
    • 實例:括號匹配,
    • 實例:棧混洗
    • 聯系,n個括號構成的合理種類和n個元素棧混洗的數目是一致的。
  • 延遲緩存
    • 線性掃描算法模式中,在預讀足夠長之后,方能確定可處理的前綴。
    • 表達式求值
    • 求RPN, 中綴轉后綴表達式
    • 這里核心的概念是優先級表的構造, 對于表達式求值來說,比如說輸入10個數,我們并不能確定其全部的
      計算順序,只能確定其部分比如, (1+2)*3-5/6....我們知道可以優先計算1+2是,然后可以計算乘法,接下來
      除法該不該計算取決于后面的符號。這種知道誰該先計算就是優先級表的概念。因為我們直到遇到)才可以去
      計算+法,此時我們必須將+先存儲起來,這里就是使用棧進行村粗。
    • 求后綴表達式的核心和表達式求值是一個道理。
  • 棧式計算(完全不了解)
    • 基于棧結構的特定計算
  • 解題思路: 應用充分性而不是必要性。

    https://www.zhihu.com/question/30469121

    舉例: 我們家人很高,充分條件,我們家人,即當人是我們家人的時候,結論身高很高。

    當滿足條件A,就可以推出結論B

    結婚需要買房, 買房即使結婚的必要條件。
    根據結論B,可以推出條件A,同時也可以推出C,結婚只是一個條件之一。

    棧的小結

    在很多的算法中,我們往往需要構造一個輔助棧來幫幫助我們延遲緩存和逆序輸出。對于逆序輸出來說,這個沒什么好說的,
    就是要記得有這個逆序的思想。最為經典的我認為莫過于二叉樹的逆層次遍歷。完全利用倒置的思想。還有就是回朔法,也是
    利用棧的這個逆序的思想,深度優先遍歷算是回朔法的一種吧。

    遞歸嵌套,理解的不深

    棧的習題

    N皇后問題

    struct Queen { public: Queen () = default;Queen (int xx, int yy): x(xx), y(yy) {}bool operator==(const Queen &rvalue){if(x == rvalue.x || y == rvalue.y ||x + y == rvalue.x + rvalue.y ||y - x == rvalue.y - rvalue.x)return true;return false;}int x;int y; }; std::ostream & operator<<(std::ostream &os, const Queen q) {os << q.x << "," << q.y ;return os; } const int N = 10; int chessboard[N][N];// 整體思路 // 1 如果皇后和已放置皇后序列不沖突,則加入皇后序列, 行號+1 goto 2, 否則改變當前皇后列的位置 goto 1 // 2 每行放置一個皇后 // 3 如果在皇后沒有放完的情況下,無法放置。則重新改變上一個皇后的列 goto 1。void placeQueen() {vector<Queen> s;Queen q(0, 0);while(s.size() < N){while(count(s.begin(), s.end(), q) && q.y < N){++q.y;}if( q.y < N){s.push_back(q);++q.x;q.y = 0;}else{if(!s.size()){cout << "no solution" << endl ;return ;}q = s[s.size() - 1];s.pop_back();++q.y;}}for(auto &a : s){cout << a << endl;} }

    迷宮路徑問題

    using std::stack; // 迷宮初始可用狀態, 形成路徑狀態, 回朔狀態, 墻 typedef enum{Available, Route, BaskTrack, Wall} Status;// unknown 為未定方向,即在沒有進行方向搜索之前的狀態 // 這個設置很棒,這樣在轉向下一個方向的時候,只要加一下就可以。 typedef enum{Unkonwn, East, South, West, North, Noway} ESWN; // 定義的方向// 返回下一個方向 inline ESWN nextESWN (ESWN eswn) { return ESWN(eswn + 1);}struct Cell{int x, y;Status status;ESWN ingoing, outgoing; Cell() = default;Cell(int xx, int yy, Status s = Available, ESWN i = Unkonwn, ESWN o = Unkonwn ): x(xx), y(yy), status(s), ingoing(i), outgoing(o) {}bool operator==(const Cell &rvalue){if(x == rvalue.x && y == rvalue.y)return true;return false;} };#define Maxsize 24Cell laby[Maxsize][Maxsize];int randLaby(Cell *&startCell, Cell *&goalCell) {srand(time(NULL));int ret;int size = Maxsize/2 + rand()%(Maxsize/2);for(int i = 0; i < size; ++i){for(int j = 0; j < size; ++ j){laby[i][j] = Cell(i, j, Wall);}}for(int i = 1; i < size - 1; ++i){for(int j = 1; j < size - 1; ++j){ret = rand() % 4;if(ret){// 3/4 設置為可用laby[i][j] = Cell(i,j, Available);}}}// 設置起始點 和 結束點startCell = &laby[rand() % (size - 2) + 1][rand() % (size - 2) + 1];startCell->status = Available;goalCell = &laby[rand() % (size - 2) + 1][rand() % (size - 2) + 1];goalCell->status = Available;return size; }inline Cell* neighbour(Cell *c) {switch(c->outgoing){case East :return &laby[c->x][c->y + 1];case South :return &laby[c->x + 1][c->y];case West :return &laby[c->x][c->y - 1];case North :return &laby[c->x - 1][c->y];default:exit(-1);}return nullptr; } inline Cell* advance(Cell *c) {switch(c->outgoing){case East:c = &laby[c->x][c->y+1];c->ingoing = East;break;case South:c = &laby[c->x+1][c-> y];c-> ingoing = South;break;case West:c = &laby[c->x][c->y-1];c-> ingoing = West;break;case North:c = &laby[c->x-1][c->y];c-> ingoing = North;break;default:exit(-1);}return c; }void display(int size, Cell start, Cell goal) {system("clear");for(int i = 0; i < size; ++i){for(int j = 0; j < size; ++j){switch(laby[i][j].status){case Route : printf("*");break;case Wall:printf("#");break;case BaskTrack:printf("x");break;case Available:printf(" ");break;default :printf("-");}if(laby[i][j] == start)printf("\bS");else if(laby[i][j] == goal)printf("\bE");}printf("\n");} } bool findPath(Cell *start, Cell *goal, int size) {if(start->status != Available || goal->status != Available){return true;}stack<Cell*> s;start->status = Route;s.push(start); do{// 展示迷宮display(size, *start, *goal);getchar();Cell *c = s.top();// 開始試探if(c == goal)return true; // 試探所有方向while((c-> outgoing = nextESWN(c-> outgoing)) < Noway){// 判斷這個方向是否有路if(Available == neighbour(c)-> status) break;}// 如果所有方向都不行,就回朔if(c-> outgoing >= Noway && !s.empty()){c-> status = BaskTrack;c = s.top();s.pop();}else if( c->outgoing >= Noway && s.size() <= 1){printf("failed\n");exit(-1);} else{s.push( c = advance(c));c-> outgoing = Unkonwn;c-> status = Route;}}while(!s.empty());return false; }

    哇,這里不得不佩服鄧俊輝老師這個題的思路,非常容易理解,而且非常好閱讀

    其主要思路為: 而且關鍵的一點是要明白我們是對這個迷宮地圖做文章

  • 將start節點加入Path中。
  • 檢查Path.top() 的四個方向,尋找一個可以走的方向。
  • 如果沒有,將Path.top()的狀態設置為BackTrack(這樣下一次檢查就會pass這個方向),然后Path.pop()
  • 如果有,走向這個方向,并將當前節點的狀態設置為Route,然后將當前節點加入到Path中
  • 如果Path不為空 goto 2。
  • 因此根據這個思路可以改寫成我自己的方式。首先是迷宮的初始化,墻設置為'#',可以走的路設置為' ',
    已經走過的路設置為'',回朔過不能走的路標記為'!'。那么我判斷上下左右能不能走只要去判斷這個二維
    向量的值是否為' '就可以了。走到這一步,就將其加入路徑設置為''帶表我走過。如果剛才的上下左右都
    不能走,將其標記為'!',然后pop掉Path.top(),再重新取Path中的top來進行下一輪判斷。代碼如下。

    const int Maxsize = 24; char laby[Maxsize][Maxsize];using Point = pair<int, int>; class Laby { public: public: Laby () { init(); }void init(){srand(time(NULL));size = Maxsize / 2 + rand() % (Maxsize / 2);start.first = rand() % (size - 2) + 1;start.second = rand() % (size - 2) + 1;goal.first = rand() % (size - 2) + 1;goal.second = rand() % (size - 2) + 1;for(int i = 0; i < size; ++i){for(int j = 0; j < size; ++j){laby[i][j] = '#';}}for(int i = 1; i < size - 1; ++i){for(int j = 1; j < size - 1; ++j){if(rand() %4)laby[i][j] = ' ';}}laby[start.first][start.second] = ' ';laby[goal.first][goal.second] = ' ';}void display(){system("clear");for(int i = 0; i < size; ++i){for(int j = 0; j < size; ++j){if(i == goal.first && j == goal.second)printf("G");elseprintf("%c", laby[i][j]);}printf("\n");}}Point findAvailableDirection(Point p){for(int i = 0; i < 4; ++i){if(laby[p.first + 1][p.second] == ' ')return std::make_pair(p.first + 1, p.second);if(laby[p.first - 1][p.second] == ' ')return std::make_pair(p.first - 1, p.second);if(laby[p.first][p.second + 1] == ' ')return std::make_pair(p.first , p.second + 1);if(laby[p.first][p.second - 1] == ' ')return std::make_pair(p.first , p.second - 1);}return std::make_pair(-1, -1);}bool findPath(){stack<Point> path;path.push(start);laby[start.first][start.second] = '*';do{display();getchar();Point tmp = path.top();if(tmp == goal)return true;// 首先要找當前點中一個可以的方向, 如果四個方向都不行就返回!auto ret = findAvailableDirection(tmp);if(ret == Point(-1,-1)){// 需要回朔laby[tmp.first][tmp.second] = '!';path.pop();}else{laby[tmp.first][tmp.second] = '*';path.push(ret);}}while(!path.empty());return false;}private: Point start;Point goal;int size; }; bool operator==(Point a, Point b) {if(a.first == b.first && a.second == b.second)return true;return false; }

    表達式求值

    表達式求值基本上說只有一個核心問題,就是優先級表的問題。我們維護倆個棧,一個位操作符棧,
    一個位操作數棧,在操作符棧的進棧過程中。我們要為了進行優先計算,讓低優先級的操作符可以觸發
    一些列高優先級的操作符,從而進行運算。達到我們想要的優先級高先進行計算的目的

    #define N_OPTR 9 using Operator = enum {Add, Sub, Mul, Div, Pow, Fac, Lp, Rp, Eoe};const char pri[N_OPTR][N_OPTR] = {/*add sub mul div pow fac lp rp eoe*/ /*add*/ {'>', '>', '<', '<', '<', '<', '<', '>', '>'}, /*sub*/ {'>', '>', '<', '<', '<', '<', '<', '>', '>'}, /*mul*/ {'>', '>', '>', '>', '<', '<', '<', '>', '>'}, /*div*/ {'>', '>', '>', '>', '<', '<', '<', '>', '>'}, /*pow*/ {'>', '>', '>', '>', '>', '<', '<', '>', '>'}, /*fac*/ {'>', '>', '>', '>', '>', '>', ' ', '>', '>'}, /*lp*/ {'<', '<', '<', '<', '<', '<', '<', '=', ' '}, /*rp*/ {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, /*eoe*/ {'<', '<', '<', '<', '<', '<', '<', ' ', '='},};using namespace std;void readNumber(char *&s, Stack<float> &opnd) {opnd.push(static_cast<float>(*s - '0'));while(isdigit(*(++s))){opnd.push(opnd.pop() * 10 + *s - '0');}if(*s != '.')return ;float fraction = 1;while(isdigit(*++s)){fraction = fraction / 10;opnd.push(opnd.pop() + (*s - '0') * fraction);} }int convert(char c) {Operator op;switch(c){case '+' : op = Add; break;case '-' : op = Sub; break;case '*' : op = Mul; break;case '/' : op = Div; break;case '^' : op = Pow; break;case '!' : op = Fac; break;case '(' : op = Lp; break;case ')' : op = Rp; break;case '$' : op = Eoe; break;case '#' : op = Eoe; break;}return op; }float eval(float op1, char op, float op2) {switch(op){case '+' :return op1 + op2;case '-' :return op1 - op2;case '*' :return op1 * op2;case '/' : return op1 / op2;case '^' :return pow(op1, op2);}return -1; }float fac(float num) // 懶得寫了,遞歸了 {if(num == 0)return 1;return num * fac(num - 1); } float eval(char op, float op1) {if(op == '!')return fac(op1);return -1; }void process(char *&s, Stack<char> &optr, Stack<float> &opnd) {int rop = convert(*s);int lop; lop = convert(optr.top());switch(pri[lop][rop]){case '<' :optr.push(*s);++s;break;case '>' :if(optr.top() == '!'){float op1 = opnd.pop();char opchar = optr.pop();opnd.push(eval(opchar, op1));}else{float op2 = opnd.pop(); float op1 = opnd.pop();char opchar = optr.pop();opnd.push(eval(op1, opchar, op2));}break;case '=' :optr.pop(); ++s;break;case ' ' ://非法情況cout << "illegal expression" << endl;exit(-1);} }float evaluate(char * S) {Stack<float> opnd; Stack<char> optr;optr.push('#');char *idx = S;while(!optr.empty()){if(isdigit(*idx)){readNumber(idx, opnd);// 這個操作會導致idx恒定每次遞增}else{process(idx, optr, opnd);// 這個操作不一定導致idx每次遞增}}return opnd.top(); }void testReadNumber() {char str[100];scanf("%s", str);char *ss = str;Stack<float> opnd;readNumber(ss, opnd);cout << opnd.top() << endl; } int main() {char str[1000];while(scanf("%s", str)){printf("%f\n", evaluate(str));memset(str, 0, sizeof(str));}return 0; }

    轉載于:https://www.cnblogs.com/patientcat/p/9720284.html

    總結

    以上是生活随笔為你收集整理的邓俊辉数据结构学习-3-栈的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。