這兩天再學習了數據結構的棧和隊列,思想很簡單,可能是學習PHP那會沒有直接使用棧和隊列,寫的太少,所以用具體代碼實現的時候出現了各種錯誤,感覺還是C語言功底不行。棧和隊列不論在面試中還是筆試中都很重要,下面就介紹一下這兩天棧和隊列的學習經驗
一:棧的學習
基礎東西:棧是在表尾進行插入和刪除的線性表,由此可知表尾是棧頂,表頭為棧底,沒有任何元素的棧是空棧。根據棧的結構可以知道:棧修改是按后進先出的原則進行的(LIFO),基本操作有插入、刪除、初始化、取棧頂元素,判斷是否是空棧等等。
棧的表示和實現:和上一節介紹過的線性表相似棧有兩種表示方法(順序表示和鏈式表示)因為和線性表類似(特殊的線性表)我只介紹順序棧的就可以了。
順序棧:利用一組連續的地址來依次存儲棧的各個元素(從棧底到棧頂),用top指針指示棧頂元素,base指針指示棧底元素,所以top=base可以作為空棧的判斷。插入一個元素top++,出棧一個元素top--,所以非空棧的指針始終在棧頂元素的下一個位置
順序棧的結構體表示:
1 //棧的順序存儲表示 2 typedef struct{ 3 SElemType *base;//在棧構造之前和銷毀后值是NULL 4 SElemType *top; 5 int stacksize; //已分配的存儲空間 6 }SqStack;
下面是我練習的代碼,實現了棧的定義、棧的初始化、進棧操作、出棧操作、得到棧頂元素、遍歷棧。需要注意的是出棧操作和得到棧頂元素的操作是有區別的,希望對大家棧的學習和回顧有所幫助。代碼都是自己練習過的,可以直接運行
1 /** 2 * 棧 3 * @author:zhaoyafei 4 * @time:2015-6-16 5 */ 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 //預定義常量 10 #define OK 1 11 #define OVERFLOW -2 12 #define ERROR 0 13 14 #define STACK_INIT_SIZE 100 //存儲空間的初始分配量 15 #define STACKINCREMENT 10 //存儲空間的分配增量stackincrement 16 17 typedef int SElemType; 18 19 //棧的順序存儲表示 20 typedef struct{ 21 SElemType *base;//在棧構造之前和銷毀后值是NULL 22 SElemType *top; 23 int stacksize; //已分配的存儲空間 24 }SqStack; 25 26 //棧的初始化操作 27 28 int InitStack(SqStack &S){ 29 S.base = (int *)malloc(STACK_INIT_SIZE * sizeof(SqStack)); 30 if(!S.base){ 31 exit(OVERFLOW);//分配空間失敗 32 } 33 S.top = S.base; 34 S.stacksize = STACK_INIT_SIZE; 35 return OK; 36 } 37 38 //進棧操作 39 int Push(SqStack &S, int e){ 40 if(S.top - S.base >= S.stacksize){//棧空間已經滿 41 S.base = (int *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SqStack)); 42 if(!S.base){ 43 exit(OVERFLOW);//分配失敗 44 } 45 S.top = S.base + S.stacksize; 46 S.stacksize += STACKINCREMENT; 47 } 48 *S.top++ = e; 49 return OK; 50 } 51 52 //出棧 53 int Pop(SqStack &S,int &e){ 54 if(S.top != S.base){ 55 e = * --S.top; 56 return OK; 57 }else{ 58 exit(OVERFLOW); 59 } 60 } 61 62 //得到頂部元素 63 void GetElem(SqStack S, int &e){ 64 if(S.top != S.base){ 65 e = * (S.top - 1); 66 }else{ 67 exit(OVERFLOW); 68 } 69 } 70 71 //打印出棧各個元素 72 void PrintfStack(SqStack S){ 73 while(*(S.top-1) && S.top != S.base){//證明不是空棧,且有值 74 S.top = S.top - 1; 75 printf("%d ",*S.top); 76 } 77 printf("\n"); 78 } 79 80 int main(){ 81 int e,i; 82 int TextData[6] = {9,2,8,1,7,6}; 83 SqStack Sa,Sb; 84 InitStack(Sa);//初始化棧Sa; 85 for(i = 0; i < 6; i++){ 86 Push(Sa,TextData[i]); 87 } 88 printf("**************棧基本操作*************\n"); 89 //初始化數據 90 printf("初始化后的Sa:"); 91 PrintfStack(Sa); 92 93 //得到棧頂元素 94 GetElem(Sa,e); 95 printf("Sa棧頂元素是:%d\n",e); 96 97 //初始化數據 98 printf("頂部出棧后Sa:"); 99 Pop(Sa,e); 100 PrintfStack(Sa); 101 }
二:隊列的學習:
隊列和棧相反,是一種先進先出(FIFO)的線性表,只能在一端進行插入,一端進行刪除
基礎:在隊列中,進行出入的一端稱作隊尾,允許刪除的一端稱作隊首。和線性表差不多可以用順序和鏈式表示。
雙端隊列:雙端隊列是限定插入和刪除的操作在表的兩端進行的線性表,用的不是很多。
循環隊列:百度上解釋:”將向量空間想象為一個首尾相接的圓環,並稱這種向量為循環向量“,其實就是把隊列首尾相連,但是要有一定的要求,不是想怎么連就怎么連。
下面給出鏈表的結構體:
1 //單鏈隊列 2 typedef struct QNode{ 3 QElemType data; 4 struct QNode *next; 5 }QNode, *QueuePtr; 6 7 typedef struct{ 8 QueuePtr front; 9 QueuePtr rear; 10 }LinkQueue; 11 12 //循環隊列 13 typedef struct{ 14 QElemType *base; 15 int front; 16 int rear; 17 }SqQueue;
下面這段代碼練習了隊列的基本操作:隊列結構體定義(比棧的稍微復雜一點)、在隊尾插入新元素、刪除隊頭元素、銷毀隊列、打印隊列、循環隊列的定義等等,這部分牽涉到好多的指針操作,如果有些困難可以在紙上划出隊列的結構,列出指針的操作前后變化,就容易多了(個人感覺如果線性表學好了,這些操作根本不在話下)。需要注意循環隊列操作中取余操作:(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
廢話不多說,下面直接給出具體實現的代碼:
1 #include <stdio.h> 2 #include <stdlib.h> 3 //頭文件 4 #define ERROR -1 5 #define OK 2; 6 #define TRUE 1; 7 #define OVERFLOW -2; 8 9 //最大隊列長度 10 #define MAXQSIZE 100 11 12 typedef int Status; 13 typedef int QElemType; 14 15 //單鏈隊列 16 typedef struct QNode{ 17 QElemType data; 18 struct QNode *next; 19 }QNode, *QueuePtr; 20 21 typedef struct{ 22 QueuePtr front; 23 QueuePtr rear; 24 }LinkQueue; 25 26 //循環隊列 27 typedef struct{ 28 QElemType *base; 29 int front; 30 int rear; 31 }SqQueue; 32 33 //********************************隊列的基本操作***************************** 34 //初始化隊列 35 Status InitQueue(LinkQueue &Q){ 36 Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));//動態分配空間 37 if(!Q.front){ 38 exit(ERROR);//分配空間失敗 39 } 40 Q.front->next = NULL; 41 return OK; 42 } 43 44 //在隊尾插入新元素 45 Status EnQueue(LinkQueue &Q, int e){ 46 QueuePtr p; 47 p = (QueuePtr)malloc(sizeof(QNode)); 48 if(!p){ 49 exit(ERROR);//分配失敗 50 } 51 p->data = e; 52 p->next = NULL; 53 Q.rear->next = p; 54 Q.rear = p; 55 return OK; 56 } 57 58 void DestroyQueue(LinkQueue &Q){ 59 if(Q.front != Q.rear){ 60 while(Q.front){ 61 Q.rear = Q.front->next; 62 free(Q.front); 63 Q.front = Q.rear; 64 } 65 } 66 } 67 68 //刪除隊頭元素,並用e返回 69 Status DeQueue(LinkQueue &Q, int &e){ 70 if(Q.front != Q.rear){//先判斷隊列是否為空 71 QueuePtr p; 72 e = Q.front->next->data; 73 if(Q.front->next == Q.rear){//隊列只有一個元素 74 p = Q.rear; 75 Q.rear = Q.front; 76 Q.front->next = NULL; 77 }else{ 78 p = Q.front->next; 79 Q.front->next = p->next; 80 p->next = NULL; 81 } 82 free(p); 83 return OK; 84 } 85 } 86 87 //打印隊列元素 88 void PrintQueue(LinkQueue Q){ 89 if(Q.front != Q.rear){ 90 do{ 91 Q.front = Q.front->next; 92 printf("%d ",Q.front->data); 93 }while(Q.front->next); 94 } 95 printf("\n"); 96 } 97 98 //********************************循環隊列的基本操作***************************** 99 //初始化隊列 100 Status InitQueueXh(SqQueue &Q){ 101 Q.base = (int *)malloc(MAXQSIZE * sizeof(int));//動態分配空間 102 if(!Q.base){ 103 exit(ERROR);//分配空間失敗 104 } 105 Q.front = Q.rear = 0; 106 return OK; 107 } 108 109 //在隊尾插入新元素 110 Status EnQueueXh(SqQueue &Q, int e){ 111 if((Q.rear + 1) % MAXQSIZE == Q.front){ 112 exit(ERROR);//隊循環列已滿 113 } 114 Q.base[Q.rear] = e; 115 Q.rear = (Q.rear + 1) % MAXQSIZE; 116 return OK; 117 } 118 119 int DestroyQueueXh(SqQueue &Q){ 120 return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE; 121 } 122 123 //刪除隊頭元素,並用e返回 124 Status DeQueueXh(SqQueue &Q, int &e){ 125 if(Q.front == Q.rear){//先判斷隊列是否為空 126 return false; 127 } 128 e = Q.base[Q.front]; 129 Q.front = (Q.front + 1) % MAXQSIZE; 130 return OK; 131 } 132 133 //打印隊列元素 134 void PrintQueueXh(SqQueue Q){ 135 if(Q.front != Q.rear){ 136 do{ 137 printf("%d ",Q.base[Q.front]); 138 Q.front++; 139 }while(Q.front != Q.rear); 140 } 141 printf("\n"); 142 } 143 144 //主方法 145 int main(){ 146 int e, i; 147 int Data[6] = {3,1,7,8,9,1}; 148 149 printf("****************隊列的基本操作**************\n"); 150 //初始化隊列 151 LinkQueue Qa, Qb; 152 InitQueue(Qa); 153 //初始化Qa 154 for(i = 0; i < 6; i++){ 155 EnQueue(Qa,Data[i]); 156 } 157 //打印Qa 158 printf("Qa的各個元素:"); 159 PrintQueue(Qa); 160 161 //刪除隊首元素 162 DeQueue(Qa,e); 163 printf("刪除Qa的隊首元素:%d\n",e); 164 printf("刪除首元素后的Qa: "); 165 PrintQueue(Qa); 166 printf("銷毀后的Qa: "); 167 DestroyQueue(Qa); 168 PrintQueue(Qa); 169 170 printf("**************循環隊列的基本操作************\n"); 171 //初始化隊列 172 SqQueue QaXh, QbXh; 173 InitQueueXh(QaXh); 174 //初始化Qa 175 for(i = 0; i < 6; i++){ 176 EnQueueXh(QaXh,Data[i]); 177 } 178 //打印Qa 179 printf("QaXh的各個元素:"); 180 PrintQueueXh(QaXh); 181 182 //刪除隊首元素 183 DeQueueXh(QaXh,e); 184 printf("刪除QaXh的隊首元素:%d\n",e); 185 printf("刪除首元素后的QaXh: "); 186 PrintQueueXh(QaXh); 187 printf("得到QaXh的元素個數:%d\n",DestroyQueueXh(QaXh)); 188 }
