棧做爲一種限定性的線性表,是將線性表的插入和刪除操做限制爲僅在表的一端進行。算法
/* 棧的常見操做: 1.初始化棧 2.元素進棧 3.元素出棧 4.棧的遍歷 5.判斷棧是否爲空棧 6.清空整個棧 */ # include <stdio.h> # include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE,* PNODE; typedef struct Stack { PNODE pTop; PNODE pBottom; }STACK, * PSTACK; void init(PSTACK pS) { pS->pTop = (PNODE)malloc(sizeof(NODE)); if (NULL == pS->pTop) { printf("動態內存分配失敗"); exit(-1); } else { pS->pBottom = pS->pTop;//若是分配成功的話,這兩個節點都指向 同一個節點(頭節點) pS->pTop->pNext = NULL; //模擬最後的那個「頭節點」pS->Bottom->pNext = NUll 也是同樣 } } void push(PSTACK pS, int val) { PNODE pNew = (PNODE)malloc(sizeof(NODE)); pNew->date = val; pNew->pNext = pS->pTop;//按照邏輯來的話,進棧時,新的元素會在棧頂,因此要pNext->pTop pS->pTop = pNew; //把新的入棧的元素做爲棧的top } void traverse(PSTACK pS) { PNODE p = pS->pTop; while (p != pS->pBottom) { printf("%d ",p->date); p = p->pNext; } printf("\n"); return; } bool empty(PSTACK pS) { if(pS->pTop == pS->pBottom) return true; //若是爲空,返回true(證實是空的) else return false; } //把pS所指向的棧出棧一次,並把出棧的元素存入pVal形參所指向的變量中, //若是出棧成功,返回true,不然返回false bool pop(PSTACK pS,int * pVal) { if (empty(pS))//pS 自己存放的就是S的地址,直接返回給empty()函數 { return false; } else { //首先須要一個指針r來指向 棧頂元素,可是若是是pS->pTop = pS->pNext 的話 //內存就沒有釋放,形成內存泄漏,因此這個方法不可取。 PNODE r = pS->pTop; *pVal = r->date; pS->pTop = r->pNext;//r 指向棧頂,因此把r的next域賦給棧頂 free(r); r = NULL; return true; } } //清空 void clear(PSTACK pS) { if(empty(pS)) { return; } else { PNODE p = pS->pTop; PNODE q = NULL; while(p!=pS->pBottom) { q = p->pNext; free(p); p = q; } //清空以後pTop 的值必定要改寫 pS->pTop = pS->pBottom; } } int main(void) { STACK S; int val; init(&S);//對棧進行初始化 ,去地址纔會放入元素 push(&S,1); push(&S,2); push(&S,3); push(&S,4); push(&S,5); push(&S,6); traverse(&S); clear(&S); //清空以後就會提示出棧失敗 if(pop(&S,&val))//須要判斷是否爲空,若是空了就沒法出棧,因此須要一個返回值,可是進棧不會滿的。 { printf("出棧成功,出棧的元素是%d\n",val); } else { printf("出棧失敗!\n"); } traverse(&S); return 0; }
全部的算法已經給出,值得注意的是在clear()
算法中 PNODE p = pS->pTop;PNODE q = NULL;
定義了兩個指針,覺得一個被free掉後就沒法進行操做了,對於pop()
函數就沒有這個問題,由於它只執行了一次 ,也就是說,只進行了一次出棧操做,而後操做完成以後才把r指針給free掉的,因此一個指針就能夠完成這個操做。 數組
隊列是另一種限定性的線性表,它只容許在表的一端插入元素,在另一端刪除元素。數據結構
/* 隊列的常見操做: 1.初始化隊列 2.元素進隊列 3.元素出隊列 4.隊列的遍歷 */ #include <stdio.h> #include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE, * PNODE;//LInkQueueNode typedef struct LinkQueue { PNODE pFront; PNODE pRear; }LINKQUEUE,* PLINKQUEUE; bool InitQueue(PLINKQUEUE pQ) { pQ->pFront= (PNODE)malloc(sizeof(NODE)); if (NULL == pQ->pFront) { printf("動態內存分配失敗!"); exit(-1); } else if(NULL != pQ->pFront) { pQ->pRear = pQ->pFront; pQ->pFront->pNext = NULL; return (true); } else return (false);//溢出 } bool EnterQueue(PLINKQUEUE pQ ,int x) { PNODE pNew = (PNODE)malloc(sizeof(NODE)); if(pNew != NULL) { pNew->date = x; pNew->pNext = NULL; pQ->pRear->pNext = pNew; pQ->pRear = pNew; return (true); } else return false; } void traverse(PLINKQUEUE pQ) { PNODE p = pQ->pFront->pNext;//注意這個地方隊列和棧的不一樣 //PNODE p = pS->pTop; while (p != pS->pBottom) 這是棧的條件 while (p) { printf("%d ",p->date); p = p->pNext; } printf("\n"); return; } bool DeleteQueue(PLINKQUEUE pQ,int * x) //出隊 { PNODE p; if (pQ->pRear==NULL) //隊列爲空 return false; p=pQ->pFront; //p指向第一個數據節點 if (pQ->pFront==pQ->pRear) //隊列中只有一個節點時 pQ->pFront=pQ->pRear=NULL;//必需要更改值,否則指針就會指向他處 else //隊列中有多個節點時 pQ->pFront=pQ->pFront->pNext; *x = p->date; free(p); return true; } int main() { LINKQUEUE Q; int x; InitQueue(&Q); EnterQueue(&Q,10); EnterQueue(&Q,20); EnterQueue(&Q,30); EnterQueue(&Q,40); traverse(&Q); DeleteQueue(&Q,&x); traverse(&Q); return 0; }
隊列的操做和棧的操做基本原理上是差很少的,值得注意的是再對隊列進行遍歷的話和棧的遍歷稍微有點差異。其中須要注意的地方已經在代碼塊中進行了說明。函數
/* 1.循環隊列初始化 2.循環隊列進隊 3.循環隊列出隊 4.循環隊列遍歷 5.循環隊列長度 */ // 實現循環隊列 #include <stdio.h> #include <stdlib.h> #define MaxSize 21 typedef int ElementType; typedef struct { int data[MaxSize]; int rear; // 隊尾指針 int front; // 隊頭指針 }Queue,*L; void InitQueue(Queue * Q ) { Q->front = Q->rear = 0; } // 元素入隊 void AddQ(Queue *PtrQ, int item) { if( (PtrQ->rear+1)%MaxSize == PtrQ->front ) { printf("隊列滿.\n"); return; } PtrQ->rear = (PtrQ->rear+1) % MaxSize; PtrQ->data[PtrQ->rear] = item; } // 刪除隊頭元素並把隊頭元素返回 int DeleteQ( Queue *PtrQ ) { if( PtrQ->front == PtrQ->rear ) { printf("隊列空.\n"); return -1; } else { PtrQ->front = (PtrQ->front+1) % MaxSize; return PtrQ->data[PtrQ->front]; } } // 隊列元素的遍歷 void print(Queue *PtrQ) { int i = PtrQ->front; if( PtrQ->front == PtrQ->rear ) { printf("隊列空."); return; } printf("隊列存在的元素以下:"); while( i != PtrQ->rear) { printf("%d ", PtrQ->data[i+1]); i++; i = i % MaxSize; } return; } int len(Queue *PtrQ) { return (PtrQ->rear-PtrQ->front+MaxSize)%MaxSize; } int main() { Queue Q; //注意不是Queue * Q; 由於數組自己就是地址吧~(emmmm,應該是,求大佬解答) int length; length = len(&Q); //用Queue * Q 的話會報錯 InitQueue(&Q); AddQ(&Q,1); AddQ(&Q,2); AddQ(&Q,3); AddQ(&Q,4); print(&Q); DeleteQ(&Q);//出隊一次 print(&Q); printf("\n循環隊列的長度爲%d",length); return 0; }
循環隊列和鏈隊列基本是一致的,之因此引入「循環隊列」是由於,對於順序列會存在「假溢出的現象」。相關概念很少作解釋,原理主要在數據結構-用C語言描述(第二版)[耿國華] 一書的p101-103。值得注意的是,在main
方法中和鏈隊列不一樣的是Queue Q;
我的認爲是利用數組模擬的緣由,由於數組自己也是利用地址傳值嘛。關於循環隊列長度計算:當rear大於front時,循環隊列的長度:rear-front,當rear小於front時,循環隊列的長度:分爲兩類計算 0+rear和Quesize-front即rear-front+Quesize。總的來講,總長度是(rear-front+Quesize)%Quesizespa
帶頭結點的循環鏈表表示隊列, 而且只設一個指針指向隊尾元素結點, 試編寫相應的隊列初始化,入隊列和出隊列的算法。.net
/* 數據結構算法題(假設以帶頭結點的循環鏈表表示隊列, * 而且只設一個指針指向隊尾元素結點(注意不設頭指針) * 試編寫相應的隊列初始化,入隊列和出隊列的算法!) */ #include<stdio.h> #include<stdlib.h> #include<time.h> #define OK 1 #define ERROR 0 typedef int QElemType; typedef int Status; typedef struct QNode { QElemType data; struct QNode * rear; struct QNode * next; }QNode,*LinkQueue; //鏈式隊列的初始化 Status InitLinkQueue(LinkQueue * L) { (*L)=(LinkQueue)malloc(sizeof(QNode)); if((*L)==NULL) { printf("內存分配失敗!\n"); return OK; } (*L)->rear=(*L); return OK; } //鏈式隊列的創建 Status Create(LinkQueue * L,int n) { srand(time(0)); LinkQueue P; for(int i=0;i<n;i++) { P=(LinkQueue)malloc(sizeof(QNode)); P->data=rand()%100+1; (*L)->rear->next=P; (*L)->rear=P; } P->next=(*L); return OK; } //入隊操做 Status EnQueue(LinkQueue * L,QElemType e) { LinkQueue P; P=(LinkQueue)malloc(sizeof(QNode)); P->data=e; P->next=(*L); (*L)->rear->next=P; (*L)->rear=P; return OK; } //出隊操做 Status DeQueue(LinkQueue * L,QElemType * e) { LinkQueue temp; *e=(*L)->next->data; temp=(*L)->next; (*L)->next=(*L)->next->next; delete(temp); return OK; } //輸出 void Print(LinkQueue * L) { LinkQueue P; P=(*L)->next; printf("輸出元素:\n"); while(P!=(*L)) { printf("%d ",P->data); P=P->next; } printf("\n"); } int main() { LinkQueue L; int ElemNumber; QElemType EnElem,DeElem; InitLinkQueue(&L); printf("請輸入元素個數:\n"); scanf("%d",&ElemNumber); Create(&L,ElemNumber); Print(&L); printf("請輸入入隊元素:\n"); scanf("%d",&EnElem); EnQueue(&L,EnElem); Print(&L); printf("出隊操做,並返回出隊元素:\n"); DeQueue(&L,&DeElem); printf("出隊元素爲:%d\n",DeElem); Print(&L); return 0; }