摘要:本文系統介紹了棧和隊列兩種基礎數據結構。棧采用"先進后出"原則,分為順序棧和鏈式棧,詳細說明了壓棧、出棧等基本操作及其實現方法。隊列遵循"先進先出"規則,同樣分為順序隊列和鏈式隊列,重點講解了循環隊列的判滿條件(犧牲一個存儲空間)和操作實現。最后通過編程練習展示了如何用鏈式棧(需兩次壓棧)和鏈式隊列(直接實現)來完成輸入輸出順序一致的功能,提供了完整的代碼實現方案。文章內容涵蓋數據結構基本概念、分類及具體實現。
一、棧
1、棧的概念:
????????1.?先進后出,后進先出
2. 棧頂:允許入棧和出棧的一端稱為棧頂
3. 棧底:不允許入棧和出棧的一端稱為棧底
4. 入棧(壓棧):將元素放入棧頂位置
5. 出棧(彈棧):將棧頂元素取出
6. 棧針:記錄棧頂位置的標記
2、棧的分類:
????????順序棧、鏈式棧
3、順序棧:
3.1 概念:
????????1. 增棧:棧的方向自低向高增長
2. 減棧:棧的方向自高向低增長
3. 空棧:棧針指向要入棧的位置
4. 滿棧:棧針指向棧頂元素的位置
3.2 順序棧的實現
3.2.1 節點的定義
3.2.2 順序棧的創建
- 申請存放標簽的空間
- 申請存放數據的空間
3.2.3?順序棧的銷毀:
- 銷毀存放數據的空間
- 銷毀存放標簽的空間
3.2.4判斷是否為空棧
- 棧針為0即為空棧
3.2.5是否為滿棧
- 棧針與tlen相同即為滿棧
3.2.6壓棧(輸入數據)
將元素放入棧頂位置
棧針位置++
3.2.7出棧
- 棧針位置--
- 將棧頂元素出棧
4、鏈式棧
4.1概念
- 使用鏈表的思想實現鏈式棧
- 參考單向鏈表節點定義
- 壓棧參考單向鏈表頭插法
- 出棧返回鏈表第一個有效節點的值,并刪除該節點
- 銷毀棧參考單向鏈表銷毀
4.2鏈式棧的實現
#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"//創建、判斷、插入頭插法、出棧、銷毀
linknode *create_empty_linkstack(void)
{
linknode *ptmpnode = NULL;
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}
ptmpnode->pnext = NULL;? ? return ptmpnode;?
}
int is_empty_linkstack(linknode *phead)
{
return NULL == phead->pnext; ? ??
}
int push_linkstack(linknode *phead,datatype tmpdata)
{
linknode *ptmpnode = NULL;
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return -1;
}
ptmpnode->data = tmpdata;
ptmpnode->pnext = phead->pnext;
phead->pnext = ptmpnode;? ? return 0;
}
datatype pop_linkstack(linknode *phead)
{
linknode *ptmpnode = NULL;
datatype deledata;? ? ptmpnode = phead->pnext;
deledata = ptmpnode->data;
phead->pnext = ptmpnode->pnext;
free(ptmpnode);
return deledata; ??
}
int destroy_linkstack(linknode **pphead)
{
linknode *ptmpnode = NULL;
linknode *pfreenode = NULL;? ? ptmpnode = *pphead;
pfreenode = *pphead;
while (ptmpnode != NULL)
{
ptmpnode = ptmpnode->pnext;
free(pfreenode);
pfreenode = ptmpnode;
}
*pphead = NULL;? ? return 0;
}
二、隊列
1、概念:
????????1. 先進先出,后進后出
2. 隊頭:出隊的一端
3. 隊尾:入隊的一端
4. 入隊:將元素放入隊列末尾
5. 出隊:將元素從隊頭中取出
2、分類:
? ? ? ? 順序隊列(循環隊列)、鏈式隊列
3、順序隊列
3.1基本類型
3.2順序隊列的實現
3.2.1順序隊列的創建
3.2.2順序隊列銷毀
3.2.3判斷順序隊列是否為空
3.2.4?判斷順序隊列是否為滿
- 為避免循環隊列空與滿的條件沖突,犧牲一個存放數據的空間,將tail+1 == head作為判斷隊滿的條件
- 循環隊列如果head或者tail下標超過tlen范圍,需要對tlen取余,保障head和tail的值在隊列下標范圍內變
3.2.5順序隊列入隊
3.2.6順序隊列出隊
4、鏈式隊列
4.1概念
- 使用鏈表的思想實現鏈式棧
- 參考單向鏈表節點定義
- 壓棧參考單向鏈表尾插法
- 出棧返回鏈表第一個有效節點的值,并刪除該節點
- 銷毀棧參考單向鏈表銷毀
4.2鏈式隊列的實現
#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>//創建、判斷、插入只能尾插法、出隊、銷毀
linknode *create_empty_linkqueue(void)
{?
//單向鏈表創建? ? linknode *ptmpqueue = NULL;
ptmpqueue = malloc( sizeof(linknode));
if (NULL == ptmpqueue)
{
perror("fail to malloc");
return NULL;
}
ptmpqueue->pnext = NULL;
return ptmpqueue;
}int is_empty_linkqueue(linknode *phead)
{
//鏈式隊判斷是否為NULL? ? return NULL == phead->pnext;?
}
int enter_linkqueue(linknode *phead, datatype tmpdata)
{
//尾插法
linknode *ptmpqueue = NULL;
linknode *plastqueue = NULL;? ? ptmpqueue = malloc(sizeof(linknode));
if (NULL == ptmpqueue)
{
perror("fail to malloc");
return -1;
}
ptmpqueue->data = tmpdata;
ptmpqueue->pnext = NULL;? ? plastqueue = phead;
while (plastqueue->pnext != NULL)
{
plastqueue = plastqueue->pnext;
}
plastqueue->pnext = ptmpqueue;? ? return 0;
}
datatype quit_linkqueue(linknode *phead)
{
//鏈式隊列的出隊
linknode *ptmpqueue = NULL;
datatype tmpdata;
if (is_empty_linkqueue(phead))
{
return -1;
}
ptmpqueue = phead->pnext;
phead->pnext = ptmpqueue->pnext;
tmpdata = ptmpqueue->data;
free(ptmpqueue);? ? return tmpdata;
}int destroy_linkqueue(linknode **pphead)
{
//單向隊表銷毀
linknode *ptmpqueue = NULL;
linknode *pfreequeue = NULL;? ? ptmpqueue = pfreequeue = *pphead;
while (ptmpqueue != NULL)
{
ptmpqueue = ptmpqueue->pnext;
free(pfreequeue);
pfreequeue = ptmpqueue;
}
*pphead = NULL;
return 0;
}
三、練習
題目:???實現終端輸入若干個數(-1結束),輸入和輸出順序相同
eg:輸入:1? 2? 3? 4? 5? -1
? ? ? ??輸出:1? 2? 3? 4? 5? -1
1、利用鏈式棧實現?
(1)題目分析
????????鏈式棧只能使用頭插法實現,所以輸入:1 2 3 4 5 則輸出:5 4 3 2 1 要實現題目操作需得再壓棧一次再出棧一次便可以實現
(2)注意事項
? ? ? ? 1)實現終端接收數,在循環中利用scanf接受數據,用if條件語句結束循環
? ? ? ? 2)? 利用兩個鏈式棧實現壓棧—出棧—壓棧—出棧
????????????????兩個方法實現,寫一個函數實現,在main函數中調用
(3)代碼實現
????????linkstack.h
#ifndef __LINKSTACK_H__
#define __LINKSTACK_H__typedef int datatype;
typedef struct node
{
datatype data;
struct node *pnext;
}linknode;extern linknode *create_empty_linkstack(void);
extern int is_empty_linkstack(linknode *phead);
extern int push_linkstack(linknode *phead,datatype tmpdata);
extern datatype pop_linkstack(linknode *phead);
extern int chance_linkstack(linknode *phead,linknode *phead2);#endif
????????linkstack.c
#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"linknode *create_empty_linkstack(void)
{
linknode *ptmpnode = NULL;
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}
ptmpnode->pnext = NULL;? ? return ptmpnode;
}int is_empty_linkstack(linknode *phead)
{
return NULL == phead->pnext;
}int push_linkstack(linknode *phead,datatype tmpdata)
{
linknode *ptmpnode = NULL;
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return -1;
}
ptmpnode->data = tmpdata;
ptmpnode->pnext = phead->pnext;
phead->pnext = ptmpnode;? ? return 0;
}datatype pop_linkstack(linknode *phead)
{
linknode *ptmpnode = NULL;
datatype tmpdata;? ? if (is_empty_linkstack(phead))
{
return -1;
}
ptmpnode = phead->pnext;
tmpdata = ptmpnode->data;
phead->pnext = ptmpnode->pnext;
free(ptmpnode);
return tmpdata;}
int chance_linkstack(linknode *phead,linknode *phead2)
{
linknode *ptmpnode = NULL;
linknode *ptmpnode1 = NULL;? ? datatype tmpdata;
? ? if (is_empty_linkstack(phead))
{
return -1;
}? ? ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return -1;
}
ptmpnode->pnext = phead2->pnext;
phead2->pnext = ptmpnode;?? ? tmpdata = phead->pnext->data;
ptmpnode->data = tmpdata;? ? return 0;
}
????????main.c
#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"int main(void)
{
linknode *plinkstack = NULL;
linknode *plinkstack2 = NULL;
plinkstack = create_empty_linkstack();
plinkstack2 = create_empty_linkstack();? ? while (1)
{
scanf("%d",&plinkstack->data);
if (-1 == plinkstack->data)
{
break;
}
push_linkstack(plinkstack,plinkstack->data);
}
#if 0
//查看是否入棧成功
while (!is_empty_linkstack(plinkstack))
{
printf("%d ",pop_linkstack(plinkstack));
}
printf("\n");
#endif#if 0
//難為版:自己創個函數
while (1)
{? ? ? ? if (is_empty_linkstack(plinkstack))
{
break;
}? ? ? ? chance_linkstack(plinkstack,plinkstack2);
pop_linkstack(plinkstack);? ? }
? ? while (!is_empty_linkstack(plinkstack2))
{
printf("%d ",pop_linkstack(plinkstack2));
}
printf("\n");
#endif
? ? //靈活版:簡單快捷? ? while (!is_empty_linkstack(plinkstack))
{? ? ? ? push_linkstack(plinkstack2,pop_linkstack(plinkstack));
printf("%d ",pop_linkstack(plinkstack2));
}
printf("\n");
? ? return 0;
}
#if 0
? ? ? ? 中間內容可以注釋掉
#endif
2、鏈式隊列實現
(1)題目分析:
? ? ? ? 隊列采用的就是尾插法,只需要在鏈式隊列中加入接收數據。
(2)注意事項:
????????注意事項尾插法中的找最后一個節點的條件是while(ptmpqueue->pnext != NULL)
(3)代碼實現:
????????linkqueue.h
#ifndef __LINKQUEUE_H__
#define __LINKQUEUE_H__typedef int datatype;
typedef struct node?
{
datatype data;
struct node *pnext;
}linknode;extern linknode *create_empty_linkqueue(void);
extern int is_empty_linkqueue(linknode *phead);
extern int enter_linkqueue(linknode *phead, datatype tmpdata);
extern datatype quit_linkqueue(linknode *phead);#endif
????????linkqueue.c
#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>linknode *create_empty_linkqueue(void)
{
linknode *ptmpqueue = NULL;
ptmpqueue = malloc( sizeof(linknode));
if (NULL == ptmpqueue)
{
perror("fail to malloc");
return NULL;
}
ptmpqueue->pnext = NULL;
return ptmpqueue;
}
int is_empty_linkqueue(linknode *phead)
{
return NULL == phead->pnext;
}int enter_linkqueue(linknode *phead, datatype tmpdata)
{
linknode *ptmpqueue = NULL;
linknode *plastqueue = NULL;? ? ptmpqueue = malloc(sizeof(linknode));
if (NULL == ptmpqueue)
{
perror("fail to malloc");
return -1;
}? ? ptmpqueue->data = tmpdata;
ptmpqueue->pnext = NULL;? ? plastqueue = phead;
while (plastqueue->pnext != NULL)
{
plastqueue = plastqueue->pnext;
}
plastqueue->pnext = ptmpqueue;? ? return 0;
}datatype quit_linkqueue(linknode *phead)
{
linknode *ptmpqueue = NULL;
linknode *pfreequeue = NULL;
datatype tmpdata;? ? if (is_empty_linkqueue(phead))
{
return -1;
}
ptmpqueue = phead->pnext;
phead->pnext = ptmpqueue->pnext;
tmpdata = ptmpqueue->data;
free(ptmpqueue);
return tmpdata;}
????????main.c
#include <stdio.h>
#include <stdlib.h>
#include "linkqueue.h"int main(void)
{
linknode *plinkqueue = NULL;? ? plinkqueue = create_empty_linkqueue();
? ? while (1)
{
scanf("%d",&plinkqueue->data);? ? ? ? if (-1 == plinkqueue->data)
{
break;
}
enter_linkqueue(plinkqueue,plinkqueue->data);
}? ? while (!is_empty_linkqueue(plinkqueue))
{
printf("%d",quit_linkqueue(plinkqueue));
}
printf("\n");? ? return 0;
}