什么?入門鏈表后你還在棧堆里徘徊?


highlight: vs2015

大家好晃择,我是melo蚣录,一名大二上軟件工程在讀生,經(jīng)歷了一年的摸滾立宜,現(xiàn)在已經(jīng)在工作室里邊準(zhǔn)備開發(fā)后臺(tái)項(xiàng)目啦冒萄。
不過這篇文章呢,還是想跟大家聊一聊數(shù)據(jù)結(jié)構(gòu)與算法橙数,學(xué)校也是大二上才開設(shè)了數(shù)據(jù)結(jié)構(gòu)這門課尊流,希望可以一邊學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)一邊積累后臺(tái)項(xiàng)目開發(fā)經(jīng)驗(yàn)。
上次的文章灯帮,我們已經(jīng)初步入門了數(shù)據(jù)結(jié)構(gòu):鏈表 想入門數(shù)據(jù)結(jié)構(gòu)崖技,卻總是拜倒在鏈表的石榴裙下?逻住,入門后你是否堅(jiān)持下來了呢,是不是在棧堆里邊徘徊不前了迎献,這篇帶你來攻破ta瞎访!

普通棧

知識點(diǎn)

后進(jìn)先出(只能在一端操作)

image.png

只能對棧頂(表尾)進(jìn)行插入和刪除

image.png

保證棧頂先出即可

image.png

**空棧最好是top=-1

image.png

應(yīng)用場景

1)子程序的調(diào)用:在跳往子程序前,會(huì)先將下個(gè)指令的地址存到堆棧中吁恍,直到子程序執(zhí)行完后再將地址取出扒秸,以回到原來的程序中。
2)處理遞歸調(diào)用:和子程序的調(diào)用類似冀瓦,只是除了儲(chǔ)存下一個(gè)指令的地址外伴奥,也將參數(shù)、區(qū)域變量等數(shù)據(jù)存入堆棧中翼闽。
3)表達(dá)式的轉(zhuǎn)換 [中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式] 與求值(實(shí)際解決)拾徙。
4)二叉樹的遍歷。
5)圖形的深度優(yōu)先(depth一first)搜索法感局。

數(shù)組實(shí)現(xiàn)棧

Java版

注意構(gòu)造器尼啡,是根據(jù)maxSize,然后記得this.maxSize=maxSize

class ArrayStack{
    //棧的大小
    private int maxSize;
    //維護(hù)的數(shù)組
    private int[] stack;
    //棧頂
    private int top;

    public ArrayStack() {
    }

    public ArrayStack(int maxSize) {
        this.stack = new int[maxSize];
        this.top = -1;
        this.maxSize=maxSize;
    }

    public int pop(){
        if(isEmpty()){
            throw new RuntimeException("棧已空");
        }
        return this.stack[top--];
    }

    public void push(int val){
        if(isFull()){
            throw new RuntimeException("棧已滿");
        }
        stack[++top]=val;
    }

    public boolean isFull(){
        return this.top==this.maxSize-1;
    }

    public boolean isEmpty(){
        return this.top==-1;
    }
}

C語言版

頭文件SqStack.h

#include"Common.h"

typedef struct{
    ElemType* elem;//存儲(chǔ)空間基址
    int top;//棧頂?shù)南乱晃?    int size;//當(dāng)前分配的內(nèi)存容量
    int increment;//擴(kuò)容時(shí)的增量
}SqStack; 

Status initStack_Sq(SqStack& S, int size, int inc);//初始化順序棧
Status DestroyStack_Sq(SqStack& S);//銷毀順序棧
Status StackEmpty_Sq(SqStack& S);//判斷是否為空棧
void ClearStack_Sq(SqStack& s);//清空棧
Status Push_Sq(SqStack& S, ElemType e);//元素入棧
Status Pop_Sq(SqStack& S, ElemType& e);//元素出棧,用e返回
Status GetTop_Sq(SqStack S, ElemType& e);//取棧頂元素,用e返回

頭文件Common.h

Status起別名(可觀性更好一點(diǎn)询微,類似Java中的封裝返回結(jié)果)
定義一些相關(guān)的Status返回值
定義ElemType崖瞭,方便擴(kuò)展,更換元素?cái)?shù)據(jù)類型

#include<stdio.h>
#include<stdlib.h>

//定義一些返回值
#define OK 1
#define ERROR 0
#define OVERFLOW -1

//默認(rèn)使用int類型返回值
typedef int Status;
//需要更改元素類型就在此更換int
typedef int ElemType;

源文件SqStack.cpp

#include"Common.h"
#include"SqStack.h"

//初始化順序棧
Status initStack_Sq(SqStack &S, int size, int inc) {
    S.elem = (ElemType*)malloc(size * sizeof(ElemType));
    if (S.elem == NULL || size <= 0 || inc <= 0) return ERROR;
    S.size = size;
    S.increment = inc;
    S.top = 0;
    return OK;
}

//銷毀順序棧
Status DestroyStack_Sq(SqStack &S) {
    S.top = 0;
    S.size = 0;
    S.increment = 0;
    free(S.elem);
    /*此處后來發(fā)現(xiàn),free操作并不會(huì)改變指針的值
        (所以并不會(huì)變成NULL),只是讓他所指向的內(nèi)存空間失效了,
        不能正常訪問了而已
        */
    /*
        //若銷毀失敗
    if (S.elem!=NULL) return ERROR;
        */
    return OK;
}

//判斷是否為空棧
Status StackEmpty_Sq(SqStack& S) {
    return S.top == 0;
}

//清空棧
void ClearStack_Sq(SqStack& S) {
    S.top = 0;
}

//元素入棧
Status Push_Sq(SqStack& S, ElemType e) {
    if (S.top >= S.size) {
        S.elem = (ElemType*)realloc(S.elem, sizeof(ElemType) * (S.size + S.increment));
    }
    if (S.elem == NULL) return ERROR;
    S.elem[S.top] = e;
    S.top++;
    return OK;
}

//元素出棧,用e返回
Status Pop_Sq(SqStack& S, ElemType& e) {
    if (StackEmpty_Sq(S)) return ERROR;
    e = S.elem[--S.top];
    return OK;
}

//取棧頂元素,用e返回
Status GetTop_Sq(SqStack S, ElemType& e) {
    if (StackEmpty_Sq(S)) return ERROR;
    e = S.elem[S.top-1];
    return OK;
}

注意

此處有點(diǎn)小問題喔拓提,就是棧的銷毀操作读恃,起初我是

free(S.elem);
//若銷毀失敗 
if (S.elem!=NULL) {
    return ERROR; 
}

后來再回過頭來看這篇博客的時(shí)候,發(fā)現(xiàn)free后其實(shí)S.elem并不會(huì)等于NULL代态,為此我又整理了一篇關(guān)于"迷途"指針的問題寺惫,具體可參照 迷途指針

鏈棧

**判空

當(dāng)top指針剛好指向基址的時(shí)候,說明此時(shí)鏈棧為空

image.png

入棧(滿了就擴(kuò)容)

直接S.top==NULL蹦疑,就是棧滿了的情況

image.png
#include "allinclude.h"  //DO NOT edit this line
Status Push_Sq2(SqStack2 &S, ElemType e) { 
    // Add your code here
    //其實(shí)可以直接S.top==NULL即可
    if(*(S.top)>=S.size){
        S.elem=(ElemType*)realloc(S.elem,sizeof(ElemType)*(S.size+S.increment));
        if(S.elem==NULL) return ERROR;
    }  
     *(S.top)=e;
     S.top++;
     return OK;
}

進(jìn)制轉(zhuǎn)換

image.png
#include "allinclude.h"
void Conversion(int N, int rd)
{  // Add your code here
  SqStack stack;
  //初始化棧
  InitStack_Sq(stack,10,1);
  //N>0  
  while(N>0){
    Push_Sq(stack,N%rd);
    N/=rd;
  }
  //再出棧便可實(shí)現(xiàn)逆序打印出來(因?yàn)闂5奶匦?
  while(!StackEmpty_Sq(stack)){
    ElemType temp;
    Pop_Sq(stack,temp);
    printf("%d",temp);
  }

}

括號匹配

(力扣)20有效的括號

https://leetcode-cn.com/problems/valid-parentheses/

最初版本

思路

  • 特判右括號西雀,判斷是否跟棧頂元素匹配
    • 若棧已經(jīng)為空了,說明左括號不夠用來匹配歉摧,無效
    • 若不匹配艇肴,也無效
    • 若匹配,則將匹配到的左括號出棧叁温,暫時(shí)有效
  • 其他情況(左括號)直接壓入棧
  • 最后出循環(huán)的時(shí)候再悼,若棧中還有元素說明左括號沒有被匹配完,也無效

細(xì)節(jié)

  • 有不符合的直接return false

優(yōu)化

  • 奇數(shù)個(gè)直接無效
bool isValid(char * s){
    int length = strlen(s);
    //初始化為-1
    int top=-1;
    char stack[length] ;
    //若本身就是奇數(shù)個(gè),則直接無效
    if(length%2!=0){
        return false;
    }
    //遍歷字符串
    for(int i=0;i<length;i++){
        //特判右括號
        if(s[i]==')'){
            //若棧已空或者棧頂元素不匹配,直接false
            if(top<0||stack[top]!='('){
                return false;
            }
            //否則將匹配到的左括號出棧
            top--;
        }
        //同理
        else if(s[i]=='}'){
            if(top<0||stack[top]!='{'){
                return false;
            }
            top--;
        }
        else if(s[i]==']'){
            if(top<0||stack[top]!='['){
                return false;
            }
            top--;
        }
        //若是左括號.直接加入棧
        else stack[++top]=s[i];
    }
    //出來時(shí)若棧不為空,說明沒有完全匹配掉
    if(top!=-1){
        return false;
    }
    return true;
}

改進(jìn)版本

  • 先統(tǒng)一處理右括號變成左括號膝但,以便后續(xù)可以直接統(tǒng)一判斷相不相等即可

細(xì)節(jié)

  • 注意要先

//若是左括號.直接加入棧
else{
stack[++top]=s[i];
continue;
}

bool isValid(char * s){
    int length = strlen(s);
    //初始化為-1
    int top=-1;
    char stack[length] ;
    //若本身就是奇數(shù)個(gè),則直接無效
    if(length%2!=0){
        return false;
    }
    //遍歷字符串
    for(int i=0;i<length;i++){
        //將右括號統(tǒng)一變成左括號,后續(xù)可以直接統(tǒng)一判斷相不相等即可
        if(s[i]==')') s[i]='(';
        else if(s[i]=='}') s[i]='{';
        else if(s[i]==']') s[i]='[';

        //若是左括號.直接加入棧
        else{ 
            stack[++top]=s[i];
            continue;
        }

        //若棧已空或者棧頂元素不匹配,直接false
        if(top<0||stack[top]!=s[i]){
            return false;
        }else{
        //否則將匹配到的左括號出棧
            top--;
        }
    }
    //出來時(shí)若棧不為空,說明沒有完全匹配掉
    if(top!=-1){
        return false;
    }
    return true;
}

題解(最優(yōu))

用函數(shù)將右括號預(yù)處理包裝起來了冲九,而且如果不是右括號,會(huì)返回0跟束,直接解決了上邊的三個(gè)都不符合得再else和continue的情況

  • 要用個(gè)ch來保存!!!!!!!!!!!!!!!!!!!!!!!!莺奸,因?yàn)橹皇莻髦党蠛ⅲ瑳]有傳引用
char pairs(char a) {
    if (a == '}') return '{';
    if (a == ']') return '[';
    if (a == ')') return '(';
    return 0;
}

bool isValid(char* s) {
    int n = strlen(s);
    if (n % 2 == 1) {
        return false;
    }
    int stk[n + 1], top = 0;
    for (int i = 0; i < n; i++) {
        //注意要用個(gè)ch來保存
        char ch = pairs(s[i]);
        if (ch) {
            if (top == 0 || stk[top - 1] != ch) {
                return false;
            }
            top--;
        } else {
            stk[top++] = s[i];
        }
    }
    return top == 0;
}

細(xì)節(jié)容易出錯(cuò)版本

我這里是直接compare(exp[i]),但是沒有修改到exp[i]灭贷,他依然是右括號温学,下邊仍然拿這個(gè)來測就錯(cuò)了

#include "allinclude.h"
int compare(char str){
  if(str==')') return '(';
  if(str=='}') return '{';
  if(str==']') return '[';
  return 0;
}

Status matchBracketSequence(char* exp, int n)
{  // Add your code here
    //若是空字符串或者奇數(shù)長度,則直接不匹配
  if(n==0||n%2!=0) return false;
  SqStack stack;
  InitStack_Sq(stack,n,1);
  for(int i=0;i<n;i++){
    //若是右括號
    if(compare(exp[i])){
      ElemType temp;
      GetTop_Sq(stack,temp);
      //若非空且匹配,則出棧  
      if(stack.top==0||exp[i]!=temp){
        return false;
      }else{
        Pop_Sq(stack,temp);
      }
    }
    //若是左括號則直接入棧
    else{
      Push_Sq(stack,exp[i]);
    }
  }
  //若非空,說明左括號沒有匹配完
  if(!StackEmpty_Sq){
    return false;
  }
  return true;
}

最后

  • 最近偷懶了,一直有在認(rèn)真記錄筆記甚疟,但是卻疏于整理仗岖,沒有發(fā)出來,希望近幾天可以抽出更多時(shí)間來繼續(xù)整理隊(duì)列古拴,哈希表箩帚,排序等方面的知識
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市黄痪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盔然,老刑警劉巖桅打,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愈案,居然都是意外死亡挺尾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門站绪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遭铺,“玉大人,你說我怎么就攤上這事恢准』旯遥” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵馁筐,是天一觀的道長涂召。 經(jīng)常有香客問我,道長敏沉,這世上最難降的妖魔是什么果正? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮盟迟,結(jié)果婚禮上秋泳,老公的妹妹穿的比我還像新娘。我一直安慰自己攒菠,他們只是感情好迫皱,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著要尔,像睡著了一般舍杜。 火紅的嫁衣襯著肌膚如雪新娜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天既绩,我揣著相機(jī)與錄音概龄,去河邊找鬼。 笑死饲握,一個(gè)胖子當(dāng)著我的面吹牛私杜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播救欧,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼衰粹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笆怠?” 一聲冷哼從身側(cè)響起铝耻,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹬刷,沒想到半個(gè)月后瓢捉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡办成,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年泡态,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迂卢。...
    茶點(diǎn)故事閱讀 40,769評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡某弦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出而克,到底是詐尸還是另有隱情靶壮,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布拍摇,位于F島的核電站亮钦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏充活。R本人自食惡果不足惜蜂莉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望混卵。 院中可真熱鬧映穗,春花似錦、人聲如沸幕随。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辕录,卻和暖如春睦霎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背走诞。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工副女, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚣旱。 一個(gè)月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓碑幅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親塞绿。 傳聞我的和親對象是個(gè)殘疾皇子沟涨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容