棧+佇列的基本操作實現(嚴蔚敏版設計思路解讀c++)
阿新 • • 發佈:2019-01-12
大家好,我是集美貌與才華於一身的阿俊吶,咳咳咳…不接受任何反駁,感謝你辣麼好看還來關注我,嘿嘿嘿,讓我們進入正題叭…biu~ biu~…
這篇部落格主要是我學完資料結構(嚴蔚敏版),想記錄下來以後複習用。
- 從零搭建起棧和佇列的操作
- 順序動態棧和動態陣列的關係(棧也可用鏈式結構實現,不過不常用)
- 鏈式佇列和連結串列的關係(佇列也可用順式結構實現,不過不常用)
- 陣列與連結串列的優缺點
資料結構設計思路剖析
先聊聊基礎的順序(動態陣列)、鏈式結構(連結串列)的設計思路,再嘮嘮如何在已有基礎上衍生出比較高階的順序(動態順序棧)、鏈式結構(鏈隊)的設計
動態陣列的資料結構
//動態陣列的資料結構
typedef struct
{
int* elem;//陣列首地址
int length;//陣列長度
int listsize;//陣列可用空間
}SqList;
- 動態陣列克服了靜態陣列無法改變空間大小的缺陷
- 該資料結構也類似於面向物件思想,將動態陣列看做一個物件,其中包含了三個屬性,待會兒要實現的功能就是其操作
在動態陣列的基礎上新增限制,稍作變形,就是順序動態棧了
順序動態棧的資料結構
typedef struct
{
int* base;//棧底
int* top;//棧頂
int listsize;//可用空間大小
}SqStack;
看看動態棧是如何由動態陣列衍生而來
- base相當於動態陣列的首地址elem
- top指向最後一個有效元素的下一個位置(特性)
- top-base = 動態陣列的length
- top = base 時棧空
連結串列的資料結構
typedef struct LNode//連結串列
{
int data;//節點中的資料
struct LNode* next;//指向下一個節點的指標
}LNode,*LinkList;
在連結串列的資料結構的構成中,可分為兩大類:資料項,指標項
- 資料項可根據需要任意定義,靈活多變
- 指標項雖然永遠只佔4位,但也是可指向任意節點
在連結串列的基礎上新增首尾指標,稍作限制,就是佇列啦
鏈式佇列的資料結構
typedef struct LNode//連結串列
{
int data;
struct LNode* next;
}LNode,*LinkList;
typedef struct
{
LNode* front;//隊頭指標
LNode* rear; //隊尾指標
}LinkQueue;
看看佇列是如何由連結串列衍生而來
- 只需新增指向節點的頭尾指標即可,因為連結串列的特點是隻需要知道頭指標,就可遍歷整個連結串列;為什麼新增尾指標呢?因為佇列要求一端進,一端出,所以得充分利用頭和尾
功能構造思路
tips
資料結構的定義直接決定了其基本操作及演算法實現的難度,所以呀,我們學習資料結構一是為了掌握基本的結構定義,二是體會各種結構是如何構造而來,今後遇到實際問題時方有可能設計出不錯的資料結構
操作分為四個部分–增查改刪
線性表無論是動態陣列/棧還是連結串列/佇列,基本操作均逃不出四座大山–增查改刪,讓我們來給他們排排序
- 增加元素永遠是老大,因為最開始是0,什麼都沒有,我們需建立一個表,其餘的操作方可進行,建立一個表也就是從空表開始反覆增加(插入)元素。若是一個表都不存在,我們拿什麼查改刪
- 查詢元素是老二,為啥把它排第二,我改刪不服。若是把查詢排老四,一進行改時突然發現,我該改誰呢?同時刪也發現了這個問題,沒有改刪的物件可咋辦,誒呀呀,查你還是快回第二吧。
- 改刪元素位置順序不太重要,看需要哪個操作多,相較之下,修改元素是比較簡單的,找到元素後修改就行,而刪除在陣列中麻煩,在連結串列方便
以上的功能排序也是具體實現時的順序,只要你掌握了動態陣列和連結串列的增查改刪,
棧功能(僅有增刪,無查改)
- 入棧–增
- 出棧–刪
佇列功能(僅有增刪,無查改)
- 入隊–增
- 出隊–刪
二者由於自身特性限制,比動態陣列和連結串列的功能還少,所以實現起來也較簡單,只有兩個功能。
一個有意思的偷懶
- 值得一提的是為啥我們選擇在連結串列的頭結點後刪除,尾節點插入。
按理說無論是連結串列的頭和尾,均可進行插入刪除操作呀。那讓我們來嘮嗑嘮嗑,假設在連結串列頭結點插入,新節點指向頭結點後一個元素,頭結點指向新節點,插入成功;再看看在尾節點刪除,刪除得知道尾節點前一個節點,誒嘿,突然發現,單向連結串列只能往後找,沒法回頭呀,這時候如果想解決問題,僅有新增一個指向尾節點前一個的指標咯。若是選擇在尾部插入,尾節點直接指向新節點就大功告成,頭結點刪除也很容易。相較之下,後者少用一個指標,更為簡單,所以我們採用簡單的方法
順序結構和鏈式結構的優缺點
- 順序結構便於查詢,修改,只要定址即可;而刪除,增加需要移動位置,不便於實現
- 鏈式結構便於刪除,增加,只需改變指標指向,且當節點資訊很多時,鏈式效率極高;而對於查詢,修改,必須從頭到尾遍歷
- 二者是互補關係,各有所長,應根據實際應用選擇合適的結構
完整實現程式碼
棧實現完整程式碼
#include<iostream>
using namespace std;
#include<stdlib.h>
#define INIT_SIZE 100
#define INCREMENT 10
//top指向有元素的下一個位置
//top-base = 動態陣列的length
//base相當於動態陣列的首地址elem
typedef struct
{
int* top;
int* base;
int listsize;
}SqStack;
void InitStack(SqStack &S)
{
S.base = (int*)malloc(INIT_SIZE*sizeof(int));
S.top = S.base;
S.listsize = INIT_SIZE;
}
//入棧
void Push(SqStack &S,int e)
{
if(S.top - S.base >= S.listsize)//動態擴容
{
S.base = (int*)realloc(S.base,(S.listsize+INCREMENT)*sizeof(int));
S.top = S.base + S.listsize;//更新棧頂
S.listsize = S.listsize+INCREMENT;//更新可用空間
}
*S.top = e;
S.top++;
}
//空->true;非空->false
bool IsEmpty(SqStack S)
{
if(S.top == S.base)return true;
else return false;
}
//僅刪除棧頂,不返回值
void Pop(SqStack &S)
{
if(!IsEmpty(S))
{
S.top--;//只刪除棧頂,不彈出
}
else cout<<"棧空!"<<endl;
}
//僅返回棧頂值,不刪除
int GetTop(SqStack S)
{
if(!IsEmpty(S))
{
return *(S.top-1);
}
else return -11111;//表示空棧
}
int main()
{
SqStack S;
InitStack(S);
for(int i =0; i <10; i++)
{
Push(S,i);
cout<<GetTop(S);
}
cout<<endl;
for(int i =0; i <10; i++)
{
cout<<GetTop(S);
Pop(S);
}cout<<GetTop(S);Pop(S);
return 0;
}
佇列實現完整程式碼
#include<iostream>
using namespace std;
#include<stdlib.h>
//佇列基本操作
typedef struct QNode
{
int data;
struct QNode* next;
}QNode,LNode,*LinkList;
typedef struct
{
QNode* front;
QNode* rear;
}LinkQueue;
void InitQueue(LinkQueue &Q)
{
Q.front = Q.rear = (QNode*)malloc(sizeof(QNode));//頭尾均指向頭指標
Q.front->next = NULL;//尾部賦空
}
//尾部插入
void Enqueue(LinkQueue &Q,int data)
{
QNode* p = (QNode*)malloc(sizeof(QNode));
p->data = data;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
}
//空->true;非空->false
bool IsEmpty(LinkQueue Q)
{
if(Q.front->next) return false;
else return true;
}
//頭部刪除;注意刪除的節點為尾節點時,重新將尾節點指向頭結點
void Dequeue(LinkQueue &Q)
{
if(!IsEmpty(Q))
{
Q.front->next = Q.front->next->next;
if(IsEmpty(Q)) Q.rear = Q.front;//刪除尾節點,重新將尾指標指向頭
}
}
//獲取隊頭元素
int GetTop(LinkQueue &Q)
{
if(!IsEmpty(Q))
{
return Q.front->next->data;
}
else return -111111;
}
int main()
{//模仿棧測試,你寫一個佇列測試吧
return 0;
}