您的位置:首页 > 理论基础 > 数据结构算法

大话数据结构 第四章 栈与队列 (读书笔记)

2017-08-21 18:39 387 查看
第四章 栈与队列

4.1 开场白---弹夹中的子弹

4.2栈的定义

4.2.1栈的定义

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

4.2.2进栈出栈变化形式

 

4.3栈的抽象数据类型

ADT栈(stack)

Data

同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。

Operation

InitStack(*S):初始化操作,建立一个空栈S。

DestroyStack(*S):若栈存在,则销毁它。

ClearStack(S):将栈清空。

StackEmpty(S):若栈为空,则返回true,否则返回false。

GetTop(S, *e):若栈存在且非空,用e返回S的栈顶元素。

Push(*S, e):若栈S存在,插入新元素e到栈S中并成为栈顶元素。

Pop(*S, *e):删除栈S中栈顶元素,并用e返回其值。

StackLength(S):返回栈S的元素个数。

endADT;

4.4栈的顺序存储结构及实现

4.4.1栈的顺序存储结构

栈的结构定义:

typedef int ElemType;/*SElemType类型根据实际情况而定,这里假设为int*/

typedef struct

{

SElemType data[MAXSIZE];

int top;  /*用于栈顶指针*/

}SqStack;

 

4.4.2 栈的顺序存储结构--进栈操作

/*插入元素e为新的栈顶元素*/

Status Push(SqStack *S, SElemType e)

{

if(S->top == MAXSIZE-1) /*栈满*/

{

return ERROR;

}

S->top++;  /*栈顶指针增加一*/

S->data[S->top] = e;  /*将新插入元素赋值给栈顶空间*/

return OK;

}

 

 

 

 

 

4.4.2 栈的顺序存储结构--出栈操作

/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR*/

Status Pop(SqStack *S, SElemType *e)

{

if(S->top == -1) /*空栈*/

return ERROR;

*e = S->data[S->top]; /*将新插入元素赋值给栈顶空间*/

S->top- -;  /*栈顶指针减一*/

 

return OK;

}

 

4.5两栈共享空间

两栈共享空间的结构的代码定义:

typedef struct

{

SElemType data[MAXSIZE];

int top1;  /*栈1栈顶指针*/

int top2;  /*栈2栈顶指针*/

}SqDoubleStack;

 

 

两栈共享空间插入(push)元素操作:

/*插入元素e为新的栈顶元素*/

Status Push(SqDoubleStack *S, SElemType e, int stackNumbet)

{

if(S->top1+1 == S->top2) /*栈满,不能再push新元素了*/

return ERROR;

if(stackNumber == 1)/*栈1有元素进栈*/

S->data[++S->top1] = e;/*若栈1则先top1+1后给数组元素赋值*/

else if(stackNumber == 2)/*栈2有元素进栈*/

S->data[- -S->top2] = e;/*若栈2则先top2-1后给数组元素赋值*/

return OK;

}

 

 

两栈共享空间弹出(pop)元素操作:

/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR;*/

Status Pop(SqDoubleStack *S, SElemType *e, int stackNumbet)

{

if(stackNumber == 1)

{

if(S->top1 == -1)

return ERROR;  /*说明栈1已经是空栈,溢出*/

*e = S->data[S->top1- -];/*栈1的栈顶元素出栈*/

}

else if(stackNumber == 2)

{

If(S->top2 == MAXSIZE)

return ERROR;

*e = S->data[S->top2++];/*栈2的栈顶元素出栈*/

}

return OK;

}

 

4.6栈的链式存储结构及实现

4.6.1栈的链式存储结构

链栈的结构代码如下:

typedef struct StackNode  /*单链表*/

{

SElemType data;

struct StackNode *next;

}StackNode, *LinkStackPtr;

 

typedef struct LinkStack   /*栈*/

{

LinkStackPtr top;  /*栈顶*/

int count; /*计数*/

}LinkStack;

 

4.6.2栈的链式存储结构--进栈操作

实现代码如下:

/*插入元素e为新的栈顶元素*/

Ststus Push(LinkStack *S, SElemType e)

{

LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));

s->data = e;

s->next = S->top;/*把当前的栈顶元素赋值给新结点的直接后继*/

S->top = s;  /*将新的结点s赋值给栈顶指针*/

S->count++;

return OK;

}

 

 

 

 

4.6.3栈的链式存储结构--出栈操作

实现代码如下:

/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR;*/

Status Pop(LinkStack *S, SElemType *e)

{

LinkStackPtr p;

if(StackEmpty(*S))

return ERROR;

*e = S->top->data;

p = S->top;     /*将栈顶结点赋值给p*/

S->top = S->top->next;/*使得栈顶指针下移一位,指向后一结点*/

free(p);/*释放结点p*/

S-count--;

return OK;

}

 

4.7栈的作用

栈的引入简化
cc91
了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚集于我们要解决的问题的核心。

4.8栈的应用--递归

4.8.1斐波那契数列实现

#include <stdio.h>

int Fibonicci(int n)

{

int f;

    if(n == 1 || n == 2)

f = 1;

else

  f = Fibonicci(n-1) + Fibonicci(n - 2);

return f;

}

int main()

{

int n, i, y;

printf("Input a integer number:");

scanf("%d", &n);

y = Fibonicci(n);

printf("%d", y);

return 0;

}

 

 

4.8.2递归定义

我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称作为递归函数;

 

4.9栈的应用--四则运算表达式求值

4.9.1后缀(逆波兰)表示法定义

一种不需要括号的后缀表达式,我们也把它称作逆波兰表示。例如9 3 1 - 3 * + 10 2 / +

 

4.9.2后缀表达式计算结果

后缀表达式:9 3 1 - 3 * + 10 2 / +

规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

 

4.9.3中缀表达式转后缀表达式

中缀表达式:9 +(3 - 1)* 3 + 10 / 2  

后缀表达式:9 3 1 - 3 * + 10 2 / +

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减),则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

 

4.10队列的定义

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

 

4.11队列的抽象数据类型

ADT 队列(Queue)

Data

同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。

Operation

InitQueue(*Q):初始化操作,建立一个空对列Q。

DestroyQueue(*Q):若队列Q存在,则销毁它。

ClearQueue(*Q):将队列Q清空

QueueEmpty(*Q): 若队列Q为空,返回True,否则返回false。

GetHead(Q, *e):若队列Q存在且非空,用e返回队列Q的对头元素。

EnQueue(*Q, e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素。

DeQueue(*Q, *e): 删除队列Q中对头元素,并用e返回其值。

QueueLength(Q):返回队列Q的元素个数。

endADT;

 

 

 

4.12循环队列的顺序存储结构及其实现

4.12.1队列顺序存储的不足

出现空余却不知道要插入,产生“假溢出”现象。

 

4.12.2循环队列定义

把队列的这种头尾相接的顺序存储结构成为循环结构

 

循环队列的顺序存储结构代码如下:

typedef int QELemType;/*QElemType类型根据实际情况而定,这里假设为int*/

/*循环队列的顺序存储结构*/

typedef struct

{

QElemType data[MAXSIZE];  

int front; /*头指针*/

int rear;  /*尾指针,若队列不空,指向队列尾元素的下一个元素*/

}SqQueue;

 

循环队列的初始化代码如下:

/*初始化一个空队列*Q*/

Status InitQueue(SqQueue *Q)

{

Q->front = 0;

Q->rear = 0;

return OK;

}

 

循环队列求队列长度代码如下:

/*返回Q的元素个数,也就是队列的当前长度*/

intQueueLength(SqQueue Q)

{

return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;

}

 

循环队列的入队列操作代码如下:

/*若队列未满,则插入元素e为Q的新的队尾元素*/

Status EnQueue(SqQueue *Q, QElemType e)

{

if((Q->rear+1) % MAXSIZE == Q->front) /*队列满的判断*/

return ERROR;

Q-> data[Q->rear] = e;  /*将元素e赋值给队尾*/

Q->rear = (Q->rear + 1) % MAXSIZE; /*rear指针向后移一位置*/

   /*若到最后则转到数组头部*/

return OK;

}

循环队列的出队列操作代码如下:

/*若队列不空,则删除Q中队头元素,用e返回其值*/

Status DeQueue(SqQueue *Q, QElemType *e)

{

if(Q->front == Q->rear)  /*队列为空的判断*/

return ERROR;

*e = Q->data[Q->front];/*将对头元素赋值给e*/

Q->front = (Q->front+1) % MAXZISE;/*front指针向后移一位置*/

  /*若到最后则转到数组头部*/

return OK;

}

 

4.13队列的链式存储结构及实现

链队列的结构为:

typedef int QElemType;/*QElemType类型根据实际情况而定,这里假设为int*/

 

typedef struct QNode/*结点结构*/

{

QElemType data;

struct QNode *next;

}QNode, *QueuePtr;

 

typedef struct   /*队列的链表结构*/

{

QueuePtr front, rear; /*对头 队尾指针*/

}LinkQueue;

 

4.13.1队列的链式存储结构-----入队操作

/*插入元素e为Q的新的队尾元素*/

Status EnQueue(LinkQueue *Q, QElemType e)

{

QueuePtr s = (QueuePtr)malloc(sizeof(QNode));

if(!s)   /*存储分配失败*/

exit(OVERFLOW);

s->data = e;

s->next = NULL;

Q->rear->next = s;  /*把拥有元素e新结点s赋值给原队尾结点的后继*/

Q->rear = s;   /*把当前的s设置为队尾结点,rear指向s*/

return OK;

}

4.13.2队列的链式存储结构-----出队操作

/*若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR*/

Status DeQueue(LinkQueue *Q, QELemType *e)

{

QueuePtr p;

if(Q->front == Q-rear)

return ERROR;

p = Q->front->next; /*将欲删除的队头结点暂存给p*/

*e = p->data; /*欲删除的队头结点的值赋值给e*/

Q->front->next = p->next; /*将原队头结点后继p->next赋值给头结点后继*/

if(Q->rear == p)  /*若队头是队尾,则删除后将rear指向头结点*/

Q->rear = Q->front;

free(p);

return OK;

}

 

4.14总结回顾

4.15结尾语
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: