邓俊辉数据结构学习-3-栈
棧的學(xué)習(xí)
棧的應(yīng)用場合
- 輸出次序與處理過程顛倒,遞歸深度和輸出長度不易預(yù)知
- 不是很理解
- 實(shí)例:進(jìn)制轉(zhuǎn)換
- 大致思路:對于進(jìn)制轉(zhuǎn)換,我們一般使用的都是長除法,因此要保存每次得到的余數(shù),但是最后算下來
新的進(jìn)制的數(shù),剛好和存儲的時(shí)候是逆序的。因此利用棧輸出即可。原因是棧是FiLo后進(jìn)先出。
- 具有自相似性的問題可遞歸描述,但分支位置和嵌套深度不固定
- 實(shí)例:括號匹配,
- 實(shí)例:棧混洗
- 聯(lián)系,n個(gè)括號構(gòu)成的合理種類和n個(gè)元素棧混洗的數(shù)目是一致的。
- 線性掃描算法模式中,在預(yù)讀足夠長之后,方能確定可處理的前綴。
- 表達(dá)式求值
- 求RPN, 中綴轉(zhuǎn)后綴表達(dá)式
- 這里核心的概念是優(yōu)先級表的構(gòu)造, 對于表達(dá)式求值來說,比如說輸入10個(gè)數(shù),我們并不能確定其全部的
計(jì)算順序,只能確定其部分比如, (1+2)*3-5/6....我們知道可以優(yōu)先計(jì)算1+2是,然后可以計(jì)算乘法,接下來
除法該不該計(jì)算取決于后面的符號。這種知道誰該先計(jì)算就是優(yōu)先級表的概念。因?yàn)槲覀冎钡接龅?才可以去
計(jì)算+法,此時(shí)我們必須將+先存儲起來,這里就是使用棧進(jìn)行村粗。 - 求后綴表達(dá)式的核心和表達(dá)式求值是一個(gè)道理。
- 基于棧結(jié)構(gòu)的特定計(jì)算
解題思路: 應(yīng)用充分性而不是必要性。
https://www.zhihu.com/question/30469121
舉例: 我們家人很高,充分條件,我們家人,即當(dāng)人是我們家人的時(shí)候,結(jié)論身高很高。
當(dāng)滿足條件A,就可以推出結(jié)論B
結(jié)婚需要買房, 買房即使結(jié)婚的必要條件。
根據(jù)結(jié)論B,可以推出條件A,同時(shí)也可以推出C,結(jié)婚只是一個(gè)條件之一。
棧的小結(jié)
在很多的算法中,我們往往需要構(gòu)造一個(gè)輔助棧來幫幫助我們延遲緩存和逆序輸出。對于逆序輸出來說,這個(gè)沒什么好說的,
就是要記得有這個(gè)逆序的思想。最為經(jīng)典的我認(rèn)為莫過于二叉樹的逆層次遍歷。完全利用倒置的思想。還有就是回朔法,也是
利用棧的這個(gè)逆序的思想,深度優(yōu)先遍歷算是回朔法的一種吧。
遞歸嵌套,理解的不深
棧的習(xí)題
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, 否則改變當(dāng)前皇后列的位置 goto 1 // 2 每行放置一個(gè)皇后 // 3 如果在皇后沒有放完的情況下,無法放置。則重新改變上一個(gè)皇后的列 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; // 迷宮初始可用狀態(tài), 形成路徑狀態(tài), 回朔狀態(tài), 墻 typedef enum{Available, Route, BaskTrack, Wall} Status;// unknown 為未定方向,即在沒有進(jìn)行方向搜索之前的狀態(tài) // 這個(gè)設(shè)置很棒,這樣在轉(zhuǎn)向下一個(gè)方向的時(shí)候,只要加一下就可以。 typedef enum{Unkonwn, East, South, West, North, Noway} ESWN; // 定義的方向// 返回下一個(gè)方向 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 設(shè)置為可用laby[i][j] = Cell(i,j, Available);}}}// 設(shè)置起始點(diǎn) 和 結(jié)束點(diǎn)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){// 判斷這個(gè)方向是否有路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; }哇,這里不得不佩服鄧俊輝老師這個(gè)題的思路,非常容易理解,而且非常好閱讀
其主要思路為: 而且關(guān)鍵的一點(diǎn)是要明白我們是對這個(gè)迷宮地圖做文章
因此根據(jù)這個(gè)思路可以改寫成我自己的方式。首先是迷宮的初始化,墻設(shè)置為'#',可以走的路設(shè)置為' ',
已經(jīng)走過的路設(shè)置為'',回朔過不能走的路標(biāo)記為'!'。那么我判斷上下左右能不能走只要去判斷這個(gè)二維
向量的值是否為' '就可以了。走到這一步,就將其加入路徑設(shè)置為''帶表我走過。如果剛才的上下左右都
不能走,將其標(biāo)記為'!',然后pop掉Path.top(),再重新取Path中的top來進(jìn)行下一輪判斷。代碼如下。
表達(dá)式求值
表達(dá)式求值基本上說只有一個(gè)核心問題,就是優(yōu)先級表的問題。我們維護(hù)倆個(gè)棧,一個(gè)位操作符棧,
一個(gè)位操作數(shù)棧,在操作符棧的進(jìn)棧過程中。我們要為了進(jìn)行優(yōu)先計(jì)算,讓低優(yōu)先級的操作符可以觸發(fā)
一些列高優(yōu)先級的操作符,從而進(jìn)行運(yùn)算。達(dá)到我們想要的優(yōu)先級高先進(jìn)行計(jì)算的目的
轉(zhuǎn)載于:https://www.cnblogs.com/patientcat/p/9720284.html
總結(jié)
以上是生活随笔為你收集整理的邓俊辉数据结构学习-3-栈的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

- 上一篇: 关于一些运算((与运算)、|(或运算)、
- 下一篇: 设计模式的六大原则(个人笔记)