线性结构的应用
(1)线性结构的两种常见应用之一——栈
1.定义
一种可以实现"先进后出"的存储结构;
栈类似于箱子。
2.分类
静态栈
动态栈
3.算法
出栈
压栈
4.栈程序示例
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node{
int data;//数据域
struct Node * pNext;
}NODE,*PNODE;
typedef struct Stack{
PNODE pTop;//指向栈的顶部节点
PNODE pBottom;//指向栈的底部节点
}STACK,* PSTACK;
//函数声明
void init(PSTACK);//初始化一个空栈,使pTop和pBottom都指向头结点
void push(PSTACK,int);//存元素,压栈
void traverse(PSTACK);//遍历
bool pop(PSTACK,int *);//出栈并且返回出栈元素,还要判断出栈是否成功
bool empty(PSTACK);//判断栈是否为空
void clear(PSTACK);//清空数据
int main(){
STACK S;//等价于struct Stack S,分配一块内存空间名为S
//里面有pTop和pBottom,暂时是垃圾值
int val;
init(&S);//初始化一个空栈,使pTop和pBottom都指向头结点
push(&S,1);//存元素,压栈
push(&S,2);//存元素,压栈
traverse(&S);//遍历
//clear(&S);//清空
//traverse(&S);//遍历
if(pop(&S,&val)){//删元素,出栈
printf("出栈成功,出栈元素的是%d\n",val);
}
else{
printf("出栈失败");
}
traverse(&S);//遍历
return 0;
}
void init(PSTACK pS){
pS->pTop = (PNODE)malloc(sizeof(NODE));
if(pS->pTop==NULL){
printf("动态内存分配失败");
exit(-1);//程序终止
}
else{
pS->pBottom=pS->pTop;//空栈情况下,栈顶和栈底都指向同一个地址
//即最后一个有效节点的下一个节点
pS->pTop->pNext=NULL;//pS->pBottom->pNext==NULL
//pS的成员pTop指向的头结点的指针域为空
}
}
void push(PSTACK pS,int val){
PNODE pNew = (PNODE)malloc(sizeof(NODE));//创建新结点
pNew->data = val;
pNew->pNext = pS->pTop;//使新节点的指针域指向原来的栈顶节点,
//不能是ps->pBottom
pS->pTop = pNew;//使栈顶指向新节点地址
return ;
}
void traverse(PSTACK pS){
PNODE p = pS->pTop;//临时指针指向栈顶
while(p != pS->pBottom){//若p还没有栈底pBottom,则遍历输出
printf("%d ",p->data);//从栈顶开始输出
p=p->pNext;
}
printf("\n");
return ;
}
bool empty(PSTACK pS){
if(pS->pTop == pS->pBottom) return true;//当栈底和栈顶指向同一块地址,为空栈
else return false;
}
//把pS所指向的栈出栈一次,并把出栈的元素存入val形参所指向的变量中,
//出栈成功返回true,失败返回false
bool pop(PSTACK pS,int * pVal){
if(empty(pS)) return false;
else{
PNODE r = pS->pTop;//临时指针r指向出栈元素位置:栈顶,方便最后释放内存
*pVal = r->data;//主函数里输出出栈元素
pS->pTop = r->pNext;//栈顶指针指向原来栈顶的下一个节点地址
free(r);
r = NULL;
return true;
}
}
void clear(PSTACK pS){//清空数据,最终使栈顶和栈底指向同一个地址
if(empty(pS)){//如果栈本身为空,不需要清空
return ;
}
else{
PNODE p = pS->pTop;//临时指针P指向栈顶
PNODE q = NULL;//临时指针q暂时设为NULL
while(p != pS->pBottom){//当栈顶指针不指向栈底时,栈不为空
q = p->pNext;//临时指针q指向下一个节点
free(p);//释放p的内存
p = q;//再使p指向下一节点地址
}
}
pS->pTop = pS->pBottom;//最后数据全部清空,栈顶和栈底指向同一个地址
}
5.应用
函数调用
中断
表达式求值
内存分配
缓冲处理
迷宫
(2)线性结构的两种常见应用之二——队列
1.定义
一种可以实现"先进先出"的存储结构
2.分类
链式队列——用链表实现
静态队列——用数组实现
静态队列通常都必须是循环队列
3.循环队列的讲解
①循环队列需要几个参数来确定?
需要2个参数来确定
②循环队列各参数的含义
2个参数在不同场合有不同的含义,建议初学者先记住,然后慢慢体会。
队列初始化:front和real的值都是零
队列非空:front代表的是队列的第一个元素,real代表的是队列的最后一个有效元素的下一个元素
队列空:front和real的值相等,但不一定是零
③循环队列入队伪算法讲解
入队伪算法演示(两步完成):
先将值存入real所代表的位置
再移动real
× real = real+1; //这样的写法是错误的
√ real = (real+1)%len; //这样的写法是正确的,其中,len为数组长度
④循环队列出队伪算法讲解
出队伪算法演示(一步完成):
√ front= (front+1)%len;
也可以先把出队的值保存起来,再移动front,通过两部完成
⑤如何判断循环队列是否为空
如果front与real的值相等,则该队列为空。
⑥如何判断循环队列是否已满
预备知识:
front 的值可能比 real 的值大;
front 的值可能比 real 的值小;
front 的值和 real 的值当然也可能相等。
两种方式判断队列是否已满:
多增加一个标识参数 或 少用一个元素【通常采用"少用一个元素的方式"】
如果r和f紧挨着,则队列已满
用C语言伪算法表示为:
if ( (r+1)%len == f )
已满;
else
不满;
4.循环队列程序示例
#include <stdio.h>
#include <malloc.h>
typedef struct Queue
{
int * pBase;
int front;
int real;
}QUEUE;
void init(QUEUE *);
bool en_queue(QUEUE *, int); //入队
void traverse(QUEUE *);
bool full_queue(QUEUE *);
bool empty_queue(QUEUE *);
bool out_queue(QUEUE *, int *);
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); //数组长度为6,只能打印到5
en_queue(&Q, 6);
en_queue(&Q, 7);
*/
traverse(&Q);
if ( out_queue(&Q, &val) )
{
printf("出队成功,出队的元素是:%d\n", val);
}
else
printf("出队失败!\n");
traverse(&Q);
return 0;
}
void init(QUEUE * pQ)
{
pQ->pBase = (int *)malloc(sizeof(int) * 6);
pQ->front = 0;
pQ->real = 0;
}
bool full_queue(QUEUE * pQ)
{
if ((pQ->real + 1) % 6 == pQ->front)
{
return true;
}
else
return false;
}
bool en_queue(QUEUE * pQ, int val)
{
if (full_queue(pQ))
{
return false;
}
else
{
pQ->pBase[pQ->real] = val;
pQ->real = (pQ->real + 1) %6;
return true;
}
}
void traverse(QUEUE * pQ)
{
int i = pQ->front;
while (i != pQ->real)
{
printf("%d ", pQ->pBase[i]);
i = (i + 1) % 6;
}
printf("\n");
return;
}
bool empty_queue(QUEUE * pQ)
{
if ( pQ->front == pQ->real )
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;
return true;
}
}
5.队列的应用
所有和时间有关的操作都有队列的影子