线性表之栈与队列

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

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

允许插入和删除的一端称为栈顶,另一端称为栈底,不包含任何数据元素的栈称为空栈,栈称为后进先出  LIFO结构

栈的抽象数据类型

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

二。栈的顺序存储结构

定义一个top变量来指示栈顶元素在数组中的位置,当栈存在一个元素时,top等于0

因此把空栈的判定条件定义为top 等于-1

栈的结构定义

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

typedef struct

{

SElemType data[MAXSIZE];

int top; 用于栈顶指针

} sqStack;

进栈操作push   插入元素e为新的栈顶元素

Status Push(SqStack *S,SElemType e)

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

{

return ERROR;

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

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

return OK;

}

出栈操作pop  若栈不空 则删除S的栈顶元素,用e返回其值,并返回OK 否则返回错误

Status Pop(SqStack *S,SElemType *e)

if(S->top==-1)

return ERROR;

*e=S->data[S->top];   将要赋值的栈顶元素赋值给e

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

return OK;

两栈共享空间   top1+1=top2

栈1为空时,就是top1等于-1时;而当top2等于n时,即是栈2为空时

若栈2是空栈,栈1的top1等于n-1时,就是栈1满了。反之,当栈1为空栈时,top2等于0时,为栈2满。

两栈共享空间结构

typedef struct

{

SElemType data[MAXSIZE];

int top1; 栈1栈顶指针

int top2; 栈2栈顶指针

}SqDoubleStack;

进栈操作

Status Push(sqDoubleStack *S,SElemType e,int stackNumber)

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方法

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

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; 说明栈2已经是空栈溢出

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

return OK;

栈的链式存储结构即链栈   栈顶  an    栈底  a1

链栈结构

typedef struct StackNode

SElemType data;

struct StackNode *next;

}StackNode,*LinkStackPtr;

typedef struct LinkStack

LinkStackPtr top;

int count;

}LinkStack;

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

假设元素值为e的新结点为s,top为栈的栈顶指针

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

Status 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;

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

若栈不空,则删除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;

栈的应用---递归

把一个直接调用自己或通过一系列的调用语句间接的调用自己的函数:称作递归函数

9+(3-1)* 3+10/2

仔细观察后发现,括号都是成对出现的,有左括号就一定有右括号,对于多重括号,最终也是完全嵌套匹配的,这用栈架构正好合适,只有碰到左括号,就将此左括号进栈,不管表达式有多少重括号,反正遇到左括号就进栈,而后面出现右括号时,就让栈顶的左括号出栈,期间让数字运算,这样,最终有括号的表达式从左到右巡查一遍,栈应该是由空到有元素,最终再因全部匹配成功后成为空栈的结果。

转化成 9 3 1 - 3 * + 10 2 / +   后缀表达式 叫后缀的原因 所有符号都是在要运算数字的后面出现

我们平时所用的标准四则运算表达式9+(3-1)* 3+10/2  叫做中缀表达式 转变成后缀表达式。规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

队列的定义:是只允许在一端进行插入操作,而在另一端进行删除操作的线性表

先进先出 允许插入的一端称为队尾,允许删除的一端称为队头

队列的抽象数据类型

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

循环队列

队列顺序存储的不足:假设一个队列有n个元素,则顺序存储的队列需要建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即是队头,所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度是O(1)。与栈不同的是,队列元素的出列是在队头,即下标是0的位置,那也就意味着,队列中的所有元素都得向前移动,以保证队列的队头,也就是下标为0的位置不为空,此时时间复杂度O(n)。

现实当中,你上了公交车,发现前排有2个空座位,而后排所有座位都已经坐满,你会怎么做?立马下车,并对自己说,后面没坐了,我等下一辆?没有这么笨的人,前面有座位,当然也是可以坐的除非坐满了,才会考虑下一辆。 这种前排有座 而后排没人坐的情况 叫做 假溢出

我们把队列的头尾相接的顺序存储结构称为循环队列。

循环队列的顺序存储结构

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

typedef struct

QElemType data[MAXSIZE];

int front;     头指针

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

}SqQueue;

循环队列的初始化

Status InitQueue (SqQueue *Q)

Q->front=0;

Q->rear=0;

return OK;

循环队列求队列长度

int QueueLength(SqQueue Q)

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

循环队列的入队操作

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;

循环队列的出队列操作

Status DeQueue(SqQueue *Q,QElemType *e)

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

return ERROR;

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

Q->front=(Q->front+1)%MAXSIZE; front指针向后移一位置 若到最后则转到数组头部

return OK;

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

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列

链队列的结构为

typedef int QElemType;

typedef struct QNode   结点结构

QElemType data;

struct QNode *next;

}QNode,*QueuePtr;

typedef struct      队列的链表结构

QueuePtr front,rear;  队头队尾指针

}LinkQueue;

入队操作

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;

出队操作

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;

时间: 2024-10-12 22:48:23

线性表之栈与队列的相关文章

Learning Data Structure_2_线性表、栈和队列

一个人在学校的日子有些寂寞,但是st说男人要耐得住寂寞,做学问也是如此吧.今天看了线性表.栈和队列的内容.以下是学习记录. 线性表(list) 1.定义:0个或多个数据元素的有限序列,元素有且只有一个直接后继和一个直接前驱:基本操作ListLength.GetElem.LocateElem.ListInsert等,并集Union的实现. 2.线性表的顺序存储结构 指用一段地址连续的存储单元依次存储数据元素(c语言中用数组实现改结构):数组长度>=线性表的长度:对于任意位置的存入或取出的所需时间相

数据结构回顾之顺序存储结构中的线性表(栈与队列顺序线性表实现)

说到数据结构呢,对于一个Coder来说还是蛮重要的啦,每次看数据结构的东西都有新的收获,这两天在回顾数据结构的知识.当然啦,虽然数据结构有些是理论的东西,如果好好的理解数据结构的东西还是少不了的代码的支撑的.数据结构简单的来说吧,可以分为两大类,一个是数据的"物理存储结构",另一种是数据的"逻辑存储结构".数据的"物理存储结构"又可分为顺序的和链式的(下面将会结合着代码打印内存地址的形式来观察物理存储结构). 逻辑存储结构又可分为集合,线性, 树

<2014 05 16> 线性表、栈与队列——一个环形队列的C语言实现

栈与队列都是具有特殊存取方式的线性表,栈属于先进后出(FILO),而队列则是先进先出(FIFO).栈能够将递归问题转化为非递归问题,这是它的一个重要特性.除了FILO.FIFO这样的最普遍存取方式外,还有一些扩展的数据结构,如双端队列.双栈.超队列.超栈等,它们是一种扩展与变异结构. 线性表有顺序存储和链接存储两类,这是针对计算机的线性存储空间作出的分类.前者可以是数组,后者可以是链表.字符串是线性表最常见的应用. 这里我用C语言实现了一个基于数组环形队列,它具有固定的队列空间.相比于链表实现,

数据结构和算法 (二)数据结构基础、线性表、栈和队列、数组和字符串

Java面试宝典之数据结构基础 —— 线性表篇 一.数据结构概念 用我的理解,数据结构包含数据和结构,通俗一点就是将数据按照一定的结构组合起来,不同的组合方式会有不同的效率,使用不同的场景,如此而已.比 如我们最常用的数组,就是一种数据结构,有独特的承载数据的方式,按顺序排列,其特点就是你可以根据下标快速查找元素,但是因为在数组中插入和删除元素会 有其它元素较大幅度的便宜,所以会带来较多的消耗,所以因为这种特点,使得数组适合:查询比较频繁,增.删比较少的情况,这就是数据结构的概念.数据结构 包括

数据结构学习笔记(特殊的线性表:栈与队列)

栈与队列 栈是限定仅在表尾(栈顶)进行插入和删除操作的线性表(后进先出).队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表(先进先出). 栈(Stack): 1.下标为0的一端作为栈底比较好,因为首元素都存在栈底,变化最小,所以让它作为栈底.定义一个top变量来指示栈顶元素在数组中的位置.栈顶位置top必须小于存储栈长度StackSize,把空栈的判定条件定位top等于-1. 2.进栈与出栈操作(顺序存储结构): 进栈操作push:/*插入元素e为新的栈顶元素*/Status Pu

线性表、栈和队列

一.线性表(list) 1.定义:有序.有限的数据序列,其中的每个数据称为元素(element). 注:在这里本文中所指的元素的数据类型相同. 2.基本概念:空(empty).长度(length).头(head).尾(tail).有序表(sorted list).无序表(unsorted list) 3.基本操作:初始化.插入.删除.访问.修改 4.用抽象类(Abstract Base Class)表示: template <typename E> class List { private:

数据结构之线性表、栈、队列

温故而知新~~~~ 一.线性表 顺序表实现(C++) 1 template<typename E> 2 class AList 3 { 4 private: 5 int maxSize; 6 int listSize; 7 int curr; 8 E* listArray; 9 public: 10 AList(int size = defaultSize) 11 { 12 maxSize = size; 13 listSize = curr = 0; 14 listArray = new E

《数据结构与算法分析:C语言描述_原书第二版》CH3表、栈和队列_reading notes

表.栈和队列是最简单和最基本的三种数据结构.基本上,每一个有意义的程序都将明晰地至少使用一种这样的数据结构,比如栈在程序中总是要间接地用到,不管你在程序中是否做了生命. 本章学习重点: 理解抽象数据类型(ADT)的概念 学习如何对表进行有效的操作 熟悉栈ADT及其在实现递归方面的应用 熟悉队列ADT及其在操作系统和算法设计中的应用 ADT 抽象数据类型(abstract data type)是一个操作的集合,是数学的抽象,在ADT中不涉及如何实现操作的集合,这可以看作是模块化设计的扩充. 对于每

数据结构与算法分析(5)表、栈和队列(一)

      本节讨论最简单和最基本的三种数据结构:表,栈和队列. 每种程序都明晰地至少使用一种这样的数据结构,而栈在程序中总要间接地用到. 内容: 1.介绍抽象数据类型(ADT)的概念; 2.阐述如何对表进行有效的操作; 3.介绍栈ADT及其在实现递归方面的应用; 4.介绍队列ADT及其在操作系统和算法设计上的与应用. (1)抽象数据类型 程序设计的基本法则之一是:例程不应超过一页. 模块化的优点: 1)调试小程序比调试大程序容易的多: 2)多个人同时对一个模块式程序编程更加容易: 3)一个写得