【数据结构】-栈与队列



栈与队列

 

一 栈:

       (Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO(Last In First Out)或先进后出FILO (First In Last Out)线性表。

    栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。

    栈底(Bottom):是固定端,又称为表头。

     空栈:当表中没有元素时称为空栈。

 

二 抽象数据类型

ADT Stack{

数据对象:D ={ ai|ai∈ElemSet,  i=1,2,…,nn≥0 }

数据关系:R ={<ai-1, ai>|ai-1ai∈D,  i=2,3,…,n }

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

} ADT Stack

 

typedef struct sqstack

{  

ElemType  *bottom;    /*  栈不存在时值为NULL  */

ElemType  *top;     /*  栈顶指针  */

int   stacksize ;      /* 当前已分配空间,以元素为单位 */

}SqStack ;

 

 

三 栈的顺序存储

动态顺序栈:指的是栈的大小可以根据需要增加。

结点进栈:首先将数据元素保存到栈顶(top所指的当前位置),然后执行top1,使top指向栈顶的下一个存储位置;

结点出栈:首先执行top1,使top指向栈顶元素的存储位置,然后将栈顶元素取出。

基本操作

一 初始化

Status Init_Stack(void)

{  

SqStack S ;

S.bottom=(ElemType *)malloc(STACK_SIZE*sizeof(ElemType));

if (! S.bottom) return  ERROR;

S.top=S.bottom ;    /*  栈空时栈顶和栈底指针相同  */

S. stacksize=STACK_SIZE;

return OK ;

}

 

 

二 压栈

Status push(SqStack S , ElemType  e)

{ 

if (S.top-S.bottom>=S. stacksize-1)

{

 

S.bottom=(ElemType*)realloc((S.STACKINCREMENT+STACK_SIZE)*sizeof(ElemType));   /*  栈满,追加存储空间  */

if (! S.bottom)  return ERROR;

S.top=S.bottom+S.stacksize ;

S.stacksize+=STACKINCREMENT ;

} 

*S.top=e;  S.top++ ; /* 栈顶指针加1e成为新的栈顶 */

return OK;

}

 

三 弹栈

Status pop( SqStack   S, ElemType *e )     

/*弹出栈顶元素*/

{  

if ( S.top==S.bottom ) 

return ERROR ;       /*  栈空,返回失败标志  */

S.top-- ;

e=*S. top ; 

return  OK ;

}

 

 

静态顺序栈

采用静态一维数组来存储栈。

栈底固定不变的,而栈顶则随着进栈和退栈操作变化的,

 

结点进栈:首先执行top1,使top指向新的栈顶位置,然后将数据元素保存到栈顶(top所指的当前位置)

结点出栈:首先把top指向的栈顶元素取出,然后执行top1,使top指向新的栈顶位置。

若栈的数组有Maxsize个元素,则top=Maxsize-1时栈满

 

 

typedef struct  sqstack

{

    ElemType  stack_array[MAX_STACK_SIZE] ;

int  top;

}SqStack ;

 

基本操作

栈初始化

SqStack Init_Stack(void)

{  

  SqStack S ;

S.bottom=S.top=0 ; 

return(S) ;

}

 

压栈

Status push(SqStack S , ElemType  e)

  /*  使数据元素e进栈成为新的栈顶  */

{ 

if  (S.top==MAX_STACK_SIZE-1)

return  ERROR;      /* 栈满,返回错误标志   */

S.top++ ;      /*  栈顶指针加1  */

S.stack_array[S.top]=e  ;   /* e成为新的栈顶  */

returnOK;        /*  压栈成功    */

}

 

弹栈

Status pop( SqStack   S, ElemType  *e )/*弹出栈顶元素*/

{ 

if ( S.top==0 )

return ERROR;       /*  栈空,返回错误标志    */

*e=S.stack_array[S.top]; 

S.top--; 

return OK; 

}

 

 

四 栈的链式存储

栈的链式存储结构称为链栈,是运算受限的单链表。其插入和删除操作只能在表头位置上进行。因此,链栈没有必要像单链表那样附加头结点,栈顶指针top就是链表的头指针。

typedef struct  Stack_Node

{ 

ElemType   data ;

structStack_Node  *next ;

} Stack_Node ;

 

链栈的基本操作

初始化:

Stack_Node  *Init_Link_Stack(void)

{   

Stack_Node  *top ;

top=(Stack_Node*)malloc(sizeof(Stack_Node )) ;

top->next=NULL;

return(top) ;

}

 

压栈:

Status push(Stack_Node *top ,ElemType  e)

{  

Stack_Node  *p ;

p=(Stack_Node  *)malloc(sizeof(Stack_Node)) ;

if (!p)  return ERROR;

/*  申请新结点失败,返回错误标志 */

p->data=e;

p->next=top->next  ;

top->next=p;    /* 钩链  */

return OK;

}

弹栈:

 

Status pop(Stack_Node  *top , ElemType *e)

/* 将栈顶元素出栈 */

{  

Stack_Node  *p ;

ElemType  e ;

if (top->next==NULL)

return ERROR;    /* 栈空,返回错误标志   */

p=top->next; e=p->data ;    /*  取栈顶元素  */

top->next=p->next;     /* 修改栈顶指针  */

free(p) ;

return OK ;

}

 

五 栈与递归

递归调用:一个函数(或过程)直接或间接地调用自己本身,简称递归(Recursive)

递归是程序设计中的一个强有力的工具。因为递归函数结构清晰,程序易读,正确性很容易得到证明。

为了使递归调用不至于无终止地进行下去,实际上有效的递归调用函数(或过程)应包括两部分:递推规则(方法),终止条件。

 

六 顺序存储队列

队列(Queue):也是运算受限的线性表。是一种先进先出(First In First Out ,简称FIFO)的线性表。只允许在表的一端进行插入,而在另一端进行删除。

   队首(front) :允许进行删除的一端称为队首。

   队尾(rear) :允许进行插入的一端称为队尾。

 

队列中没有元素时称为空队列。在空队列中依次加入元素a1, a2, …, an之后,a1是队首元素,an是队尾元素。显然退出队列的次序也只能是a1, a2, …, an ,即队列的修改是依先进先出的原则进行的

 

抽象数据类型:

ADT Queue{

数据对象:D ={ ai|ai∈ElemSet,  i=1, 2, …, n, n >= 0 }

数据关系:R = {<ai-1, ai>| ai-1, ai∈D, i=2,3,…,n }

约定a1端为队首,an端为队尾。

基本操作:

Create():创建一个空队列;

EmptyQue():若队列为空,则返回true ,否则返回flase

InsertQue(x) :向队尾插入元素x

DeleteQue(x) :删除队首元素x

} ADT Queue

 

//队列的数据结构

typedef struct  queue

{ 

ElemType   Queue_array[MAX_QUEUE_SIZE] ;

int   front ;

int  rear ;

}SqQueue;

 

利用一组连续的存储单元(一维数组)依次存放从队首到队尾的各个元素,称为顺序队列.

队列的示意图。

 

 

七 循环队列

为充分利用向量空间,克服上述“假溢出现象的方法是:将为队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列(CircularQueue)

在循环队列中进行出队、入队操作时,队首、队尾指针仍要加1,朝前移动。只不过当队首、队尾指针指向向量上界(MAX_QUEUE_SIZE-1)时,其加1操作的结果是指向向量的下界0

溢出的情况下标的计算方式是用模运算来进行计算的i=(i+1)%MAX_QUEUE_SIZE ;

◆ 循环队列为空:front=rear  

◆ 循环队列满:(rear+1)%MAX_QUEUE_SIZE =front

 

基本操作

入队

Status Insert_CirQueue(SqQueue  Q , ElemType e)

 /*  将数据元素e插入到循环队列Q的队尾 */

{ 

if  ((Q.rear+1)%MAX_QUEUE_SIZE== Q.front)

return  ERROR;      /* 队满,返回错误标志   */

Q.Queue_array[Q.rear]=e ;   /*  元素e入队  */

Q.rear=(Q.rear+1)% MAX_QUEUE_SIZE ;

/*  队尾指针向前移动  */

return OK;        /*  入队成功    */

}

 

 

 

 

 

 

出队

 

Status Delete_CirQueue(SqQueue  Q, ElemType *x )

  /*  将循环队列Q的队首元素出队  */

{  

if (

Q.front+1== Q.rear)

return error;  /*  队空,返回错误标志    */

*x=Q.Queue_array[Q.front] ;  /* 取队首元素 */

Q.front=(Q.front+1)% MAX_QUEUE_SIZE ;

    /*  队首指针向前移动  */

return OK ;

}

 

七 链队列

 

队列的链式存储结构简称为链队列,它是限制仅在表头进行删除操作和表尾进行插入操作的单链表。

需要两类不同的结点:数据元素结点,队列的队首指针和队尾指针的结点

 

typedef struct Qnode

{ 

ElemType    data ;

struct Qnode  *next ;

}QNode ;

 

 

链对列的初始化

LinkQueue *Init_LinkQueue(void)

{ LinkQueue  *Q ;  QNode *p ;

p=(QNode *)malloc(sizeof(QNode)) ; /* 开辟头结点 */

p->next=NULL ;

Q=(LinkQueue  *)malloc(sizeof(LinkQueue)) ;

       /*  开辟链队的指针结点  */

Q.front=Q.rear=p ;

return(Q) ;

}

 

 

链对列的入队

Status Insert_CirQueue(LinkQueue  *Q ,ElemType  e)

     /*  将数据元素e插入到链队列Q的队尾 */

{  

p=(QNode*)malloc(sizeof(QNode)) ;

if (!p)  return ERROR;

/*  申请新结点失败,返回错误标志 */

p->data=e; p->next=NULL ;       /*  形成新结点 */

Q.rear->next=p;  Q.rear=p ;  /*  新结点插入到队尾  */

return OK;

}

 

 

 

链对列的出队

Status Delete_LinkQueue(LinkQueue  *Q,ElemType *x)

  {  

QNode *p ;

if  (Q.front==Q.rear)  return ERROR ;    /*  队空  */

p=Q.front->next;   /* 取队首结点  */

*x=p->data;

Q.front->next=p->next;      /* 修改队首指针  */

if  (p==Q.rear) Q.rear=Q.front ;

           /*  当队列只有一个结点时应防止丢失队尾指针  */

           ree(p) ;  

return OK ;

}

链队列的撤销

void Destroy_LinkQueue(LinkQueue  *Q )

  /*  将链队列Q的队首元素出队  */

{  while  (Q.front!=NULL)

{ Q.rear=Q.front->next;  

     /*  令尾指针指向队列的第一个结点   */

free(Q.front);      /* 每次释放一个结点 */

   /*  第一次是头结点,以后是元素结点  */

Q.ront=Q.rear;

}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值