摘要:本文系统介绍了栈和队列两种基础数据结构。栈采用"先进后出"原则,分为顺序栈和链式栈,详细说明了压栈、出栈等基本操作及其实现方法。队列遵循"先进先出"规则,同样分为顺序队列和链式队列,重点讲解了循环队列的判满条件(牺牲一个存储空间)和操作实现。最后通过编程练习展示了如何用链式栈(需两次压栈)和链式队列(直接实现)来完成输入输出顺序一致的功能,提供了完整的代码实现方案。文章内容涵盖数据结构基本概念、分类及具体实现。
一、栈
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)
{
//链式队判断是否为NULLreturn 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;
}