線性結構的兩種常見應用之一 棧
定義 一種可以實現“先進後出”的存儲結構
分類
靜態棧 類似數組的結構
動態棧 類似鏈表的結構
棧的應用
(1)函數調用(所有的函數調用都是壓棧與出棧)
所謂函數A調用函數B就是把A的最後執行的一個語句的地址與調用的B函數的
所有內容壓到一個棧內部去執行,執行完畢出棧,然後地址出棧接着執行A函數
(2)中斷(中斷一個進程去執行下一個進程)
(3)表達式求值(表達式的數值部分與運算符會分開存放,利用兩個棧可以製作一個簡易計算器)
(4)內存分配(動態內存在堆中分配)
(5)緩衝處理
(6)迷宮(遊戲中的地圖,爲什麼走到一部分就走不動了)
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
# include <stdbool.h>
typedef struct Node
{
int data;
struct Node *pNext;
}NODE, *PNODE;
typedef struct Stack
{
PNODE pTop;
PNODE pBottom;
}STACK, *PSTACK;
void init(PSTACK pS);
void push(PSTACK pS, int val);
bool pop(PSTACK pS, int *pVal);
bool clear(PSTACK pS);
bool traverse(PSTACK pS);
bool is_empty(PSTACK pS);
int main(void)
{
STACK S;
int val;
init(&S);
push(&S, 1);
push(&S, 2);
//push(&S, 3);
//push(&S, 5);
//push(&S, 6);
traverse(&S);
if (pop(&S, &val))
printf("出棧成功 值爲%d \n", val);
traverse(&S);
if (pop(&S, &val))
printf("出棧成功 值爲%d \n", val);
traverse(&S);
if (clear(&S))
printf("清除成功 \n");
traverse(&S);
return 0;
}
void init(PSTACK pS)
{
PNODE pNode = (PNODE)malloc(sizeof(NODE));
if (pS == NULL)
{
printf("內存分配失敗!\n");
exit(-1);
}
pS->pTop = pNode;
pS->pBottom = pNode;
pS->pBottom->pNext = NULL;// pS->pTop->pNext = NULL;
}
void push(PSTACK pS, int val)
{
PNODE pNode = (PNODE)malloc(sizeof(NODE));
if (pS == NULL)
{
printf("內存分配失敗!\n");
exit(-1);
}
pNode->data = val;
pNode->pNext = pS->pTop;
pS->pTop = pNode;
return;
}
bool traverse(PSTACK pS)
{
if (is_empty(pS))
{
return false;
}
PNODE pNode = pS->pTop;
while (pNode != pS->pBottom) //while (pNode->pNext != NULL)
{
printf("%d ", pNode->data);
pNode = pNode->pNext;
}
printf("\n");
}
bool pop(PSTACK pS, int *pVal)
{
if (is_empty(pS))
{
return false;
}
else
{
PNODE pNode = pS->pTop;
*pVal = pNode->data;
pS->pTop = pNode->pNext;
free(pNode);
return true;
}
}
bool is_empty(PSTACK pS)
{
if (pS->pTop == pS->pBottom)
{
printf("空棧\n");
return true;
}
else
{
return false;
}
}
// 類似於 pop
bool clear(PSTACK pS)
{
if (is_empty(pS))
{
return false;
}
PNODE pNode;
while (pS->pTop != pS->pBottom)
{
pNode = pS->pTop;
pS->pTop = pNode->pNext;
free(pNode);
printf("清除中...\n");
}
}
線性結構的兩種常見應用之二 隊列
定義 一種可以實現“先進先出”的存儲結構
分類
- 鏈式隊列 用鏈表實現
- 靜態隊列 用數組實現
靜態隊列通常都必須使循環隊列
循環隊列的講解:
1. 靜態隊列爲什麼必須是循環隊列
2. 循環隊列需要幾個參數來確定 及其含義
需要2個參數來確定
front
rear
3. 循環隊列各個參數的含義
2個參數不同場合有不同的含義
1)隊列初始化
front和rear的值都是零
2)隊列非空
front代表的是隊列的第一個元素
rear代表的是隊列的最後一個有效元素的下一個元素
3)隊列空
front和rear的值相等, 但不一定是空
4. 循環隊列入隊僞算法講解
兩步完成
1. 將值存入r所代表的 位置
2.錯誤寫法 r=r+1
正確寫法 r=(r+1)% 數組的長度
5. 循環隊列出隊僞算法講解
f = (f+1)% 數組的長度
6. 如何判斷循環隊列是否爲空
判斷 front 與 rear 的值是否相等
7. 如何判斷循環隊列是否已滿
預備知識 front的值可能比rear大 也可能比reat小 也可能相等
兩種方式
1. 多增加一個標誌參數( f 和 r 相等)
2. 少用一個元素 (通常使用第二種方式)
如果 r 和 f 緊挨着,則隊列已滿
if((r +1)% 數組長度 == f )
已滿
else
不滿
# include <stdio.h>
# include <stdbool.h>
# include <stdlib.h>
typedef struct Queue
{
int * pBase;
int front;
int rear;
}QUEUE;
void init(QUEUE *);
bool en_queue(QUEUE *, int val);
void traverse_queue(QUEUE *);
bool full_queue(QUEUE *);
bool out_queue(QUEUE *, int *);
bool empty_queue(QUEUE *);
int main(void)
{
QUEUE Q;
int val;
init(&Q);
en_queue(&Q, 1);
en_queue(&Q, 2);
en_queue(&Q, 3);
en_queue(&Q, 4);
en_queue(&Q, 5);
en_queue(&Q, 6);
en_queue(&Q, 7);
en_queue(&Q, 8);
traverse_queue(&Q);
if (out_queue(&Q, &val))
{
printf("出棧成功 值爲%d\n", val);
}
else
{
printf("出棧失敗\n");
}
traverse_queue(&Q);
return 0;
}
void init(QUEUE *pQ)
{
pQ->pBase = (int *)malloc(sizeof(int) * 6);
pQ->front = 0;
pQ->rear = 0;
return;
}
bool en_queue(QUEUE * pQ, int val)
{
if (full_queue(pQ))
{
return false;
}
else
{
pQ->pBase[pQ->rear] = val;
pQ->rear = (pQ->rear + 1) % 6;
return true;
}
}
void traverse_queue(QUEUE * pQ)
{
int i;
i = pQ->front;
while (i != pQ->rear)
{
printf("%d ", pQ->pBase[i]);
i = (i + 1) % 6;
}
printf("\n");
return;
}
bool full_queue(QUEUE *pQ)
{
if ((pQ->rear + 1) % 6 == pQ->front)
{
return true;
}
else
{
return false;
}
}
bool out_queue(QUEUE *pQ, int *pVal)
{
if (empty_queue(pQ))
{
return false;
}
else
{
*pVal = pQ->pBase[pQ->front];
pQ->front = (pQ->front + 1) % 6;
}
}
bool empty_queue(QUEUE *pQ)
{
if (pQ->front == pQ->rear)
{
return true;
}
else
{
return false;
}
}