【数据结构】栈和队列

目录

一、栈的定义和特点

二、队列的定义和特点

三、栈的抽象数据类型的类型定义

四、顺序栈的表示和实现

五、链栈的表示和实现

六、队列的表示和操作的实现

七、队列的链接存储——链式队列

八、队列的顺序存储——循环队列


一、栈的定义和特点

1、栈的定义:栈是一个特殊的线性表,是限定仅在一端,通常为表尾进行插入和删除的操作。又称为后进先出的线性表,简称LIFO结构。

2、栈的相关概念:栈仅在表尾进行插入、删除的操作。

1)表尾an称为栈顶TOP;表头a1称为栈底Base

2)入栈:插入元素到栈顶(即表尾)的操作,称为入栈。

3)出栈:从栈底(即表尾)删除最后一个元素的操作,称为出栈。

4)逻辑结构:与线性表相同,任为一对一关系。

5)存储结构:用顺序栈或链栈存储均可,但以顺序栈更常见。 

6)栈与一般线性表的不同点:运算规则不同,一般线性表为随机存取,栈为后进先出(LIFO)。

二、队列的定义和特点

1)定义:只能在表的一段进行插入运算,在表的另一端进行删除运算的线性表(头插尾删)。

2)逻辑结构:与同线性表相同:任为一对一关系。

3)存储结构:顺序队或链队,以循环顺序队列更常见。

4)运算规则:只能在队首和队尾运算,且访问结点时依照先进先出(FIFO)的原则。

5)实现方式:关键是掌握入队和出队操作,具体实现依顺序队或链队的不同而不同。

三、栈的抽象数据类型的类型定义

1、ADT  Stack{

数据对象:D={ai|ai属于ElemSet,i=1,2,3....n,n>0}

数据关系:R1={<ai-1,ai>|ai-1,ai属于D,i=2,....,n}

                  约定an端为栈顶,a1端为栈底。

基本操作:初始化,进栈,出栈,取栈顶元素等

}ADT Stack

2、基本操作:

InitStack(&S):初始化操作,构造一个空栈S。

DestoryStack(&):销毁栈操作。

StackEmpty(S):判断S是否为空栈。

StackLength(S):求栈的长度。

GetTop(S,&e):取栈顶元素,用e返回S的栈顶元素。

ClearStack(&S)栈置空操作,将S清为空栈。

Push(&S,e):入栈操作。

四、顺序栈的表示和实现

1、存储方式:

1)存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端。

2)附设top指针,指示栈顶元素在顺序栈中的位置。

3)另设base指针,指示栈底元素在顺序栈中的位置。

4)但是为了方便操作,通常top指针指示真正的栈顶元素之上的下标地址。

5)另外,用stacksize表示栈可使用的最大容量。

2、栈满时的处理方法:

1)报错,返回操作系统。

2)分配更大的空间,作为栈的存储空间,将原栈移入新栈。

3、使用数组作为顺序栈存储方式的特点

1)简单,方便,但容易溢出(数组大小固定)。

2)上溢:栈已经满,又要压入元素。

3)下溢:栈已经空,还要弹出元素。

4、顺序栈的表示:

#define MAXSIZE 100
typedef struct{
          SElemType *base;  //栈底指针
          SElemType *top;    //栈顶指针
          Int stack size;         //栈可用最大容量
}SqStack;

5、顺序栈的初始化:

Status InitStack(SqStack &S){
S.base = new SElemType(MAXSIZE);
//S.base=(SElemType*)malloc(MAXSIZE*sizeo(SElemType));
if(!S.base) exit (OVERFLOW);
S.top=S.base;
S.stacksize = MAXSIZE;
return OK;}

6、得到栈顶元素

void getTop(SqStack S,ElemType &e){
if(S.Top==S.base){
return;
}
e=*(S.Top-1);
}

7、判断顺序栈是否为空

Status StackEmpty(SqStack S){
if(S.Top==S.base)
return TRUE;
else
return FALSE;
}

8、求顺序栈的长度

int StackLength(Sqstack S)
{
return S.Top-S.base;
}

9、清空顺序栈

Status ClearStack(SqStack S){
if(S.base)
S.Top=S.base;
return OK;
}

10、销毁顺序栈

Status DestroyStack(SqStack &S){
if(S.base){
delete S.base;
S.stacksize=0;
S.base=S.top=NULL;
}
return OK;
}

11、顺序栈的入栈

void push(SqStack &S,ElemType e){
if(S.top-S.base=S.size){
S.base=(ElemType*)realloc(S.base,(S.size+STACK_INCERMENT)*sizeof(ElemType));
if(!S.base){
exit(-1);
}
S.top=S.base+S.size;
S.size+=STACK_INCERMENT;
}
*(S.top++)=e;
}

12、顺序栈的出栈

void pop(SqStack &S,ElemType &e){
if(S.top==S.base){
return;
}
e=*--S.top;
}

五、链栈的表示和实现

注意:1)链表的头指针就是栈顶an

2)不需要头结点

3)基本上不存在栈满的情况

4)空栈相当于头指针指向空

5)插入和删除仅在栈顶出进行

1、链栈的初始化

void InitStack(LinkStack &L){
//构造一个空栈,栈顶指针置为空
S=NULL;
return OK;
}

2、链栈的存储表示

typedef struct StackNode{
SElemType data;
struct StackNode *next;
}*Link;
typedef struct{
Link top;
}LinkStack;

3、算法:构建一个空栈、判空、读取栈顶元素

Status InitStack(LinkStack &S){
S.top=null;
return OK;
}
Status StackEmpty(LinkStack S){
return S.top=null;
}

4、获取栈顶元素

Status GetTop(LinkStack S,SElemType &e){
if(StackEmpty(S)) return ERROR;
e=S.top->data;
return OK;
}

5、链栈的进栈

Status Push(LinkStack &S,SElemType e){
q=(Link)malloc(sizeof(StackNode));
if(!q) exit (OVERFLOW);
q->data=e;
q->next=S.top;
S.top=q;
return OK;
}

6、链栈的出栈

Status Pop(LinkStack &S,SElemType &e){
q=S.top;
if(StackEmpty(S))return ERROR;
e=q->data;
S.top=q->next;
free(q);
return OK;
}

 7、总结

1)后入栈的元素总是先出栈。

2)无论顺序表还是链栈,前述算法的T(n)=O(1)。

六、队列的表示和操作的实现

1、相关术语

1)队列(queue)是仅在表尾进行插入操作,在表头进行删除操作的线性表。

2)表尾即an端,称为队尾;表头即a1端,称为队头。

3)它是一种先进先出(fifo)的线性表。

4)插入元素称为入队,删除元素称为出队。

5)队列的存储结构为链队或顺序队。(常用循环顺序队)

2、队列的相关概念

1)定义:只在表的一端进行插入运算,在表的另一端进行删除运算的线性表(头删尾插)。

2)逻辑结构:与同线性表相同,仍为一对一关系。

3)存储结构:顺序队或链队,以循环顺序队列更常见。

4)运算规则:只能在队首和队尾运算,且访问结点时依照先进先出(fifo)的原则。

5)实现方式:关键是掌握入队和出队的操作,

3、队列的抽象数据类型定义

ADT Queue{

数据对象:D={ai|ai属于ElemSet,i=1,2....,n,n>=0}

数据关系:R={<ai-1,ai>|ai-1,ai属于D,i=1,2....,n). a1端为队头,an端为队尾。

基本操作:InitQueue(&Q) 操作结果:队列Q被销毁。

DestroyQueue(&Q) 操作结果:队列Q被销毁。

ClearQueue(&Q)  操作结果:将Q清空。

QueueLength(Q) 操作结果:返回Q的元素个数。

GetHead(Q,&e) 操作结果:用e返回Q的队头元素。

EnQueue(&Q,&e) 操作结果:插入元素为e的元素。

DeQueue(&Q,&e) 操作结果:删除Q的队头元素。

}ADT Queue

七、队列的链接存储——链式队列

1、队头在链头,队尾在链尾,设置队头,队尾指针保存队头、队尾地址。

2、链队列表示

1)结点类型:

typedef struct QNode{
QElemtype data;
struct QNode *next;
}QNode,*QueuePtr;

2)链队列类型

Typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;

3)定义一链队列:LinkQueue Q;

队头结点:Q.front->next;

队尾结点:Q.rear;

队尾结点数据:Q.rear->data;

3、链队列入队

QueuePtr EnQueue(LinkQueue Q,QElemtype x){
P=(QueuePtr)malloc(sizeof(QNode));
if(!p) exit(overflow);
p->data=x;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return Q;
}

4、链队列出队

QueuePtr DeQueue(LinkQueue Q,QElemtype &e){
if(Q.front==Q.rear)
return error;
p=Q.front->next;e=p->next;
Q.front->next=P->next;
if(Q.rear==p)
Q.rear=Q.front;
free(p);
return Q;
}

八、队列的顺序存储——循环队列

1、定义

#define SIZE 100
typedef int Elemtype;
typedef struct{
Elemtype *base;    //连续空间的起始地址
int front;                 //队头元素
int rear;                   //队尾下标,为队尾元素的下一位置
}SqQueue;
SqQueue Q{
Q.base[Q.front];      //队头元素
Q.base[Q.rear-1]; //队尾元素
Q.rear;     //入队元素的下标
}

2、注意

1)经过多次入队,出队,可能出现rear=SIZE

2)此时,队列中可能存在未用单元

3)SIZE-1的下一位置为0

4)属于队列的元素,从front出发,沿着下标递增方向,直至达到rear

5)rear指向的不是队尾,而是队尾的下一元素(故最多只能存放SIZE-1个元素)

3、区分空和满

1)为队列附设一个专门区分空或满的标志

2)约定

         ·空:front=rear

         ·满:front在rear的下一位置

4、循环队列

1)存储队列的数组被当作首尾相接长度的表处理

2)队头、队尾指针加1时从MaxSize-1直接进到0,可用c语言的取模(余数)运算实现

3)·出队:队头指针加1

              front=(front+1)%MaxSize

      ·入队:队尾指针加1

              rear=(rear+1)%MaxSize

      ·队列初始化:

              front=rear=0

4)·队空条件:front=rear

     `队满条件:(rear+1)%MaxSize=front

5、算法实现——初始化

void Init(SqQueue &Q){
Q.base=(Elemtype*)malloc(SIZE*sizeof(Elemtype));
if(!Q.base)
exit(-1);
Q.front=Q.rear=0;
}

6、得到队列长度

void getlength(SqQueue Q,int &length){
if(Q.front<=Q.rear){
length=Q.rear-Q.front;}
else
length=SIZE-(Q.front-Q.rear);
}

7、将e入队

void enter(SqQueue &Q,Elemtype e){
int len;
getlength(Q,len);
if(len==SIZE-1)
return -1;
Q.base[Q.rear]=e;  //Q.rear代表下标
if(Q.rear<=SIZE-1){
Q.rear++;
}
else
Q.rear=0;
}

8、将e出队

void remove(SqQueue &Q,Elemtype &e){
if(Q.front=Q.rear)
return;
e=Q.base[Q.front];
if(Q.front<SIZE-1){
Q.front++;
}
else
Q.front=0;
}

9、总结

1)先入队的元素总是先出队。

2)无论是循环队列还是链队列,前述各算法的T(n)=O(1)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值