栈---后进先出

如果问题求解的过程具有”后进先出"的天然特性的话,则求解的算法中也必然需要利用"栈”

栈和队列是限定插入和删除只能在表的"端点”进行的线性表。

 

栈(stack) 是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表。

表尾(即an端)称为栈顶(Top;表头(即a1端)称为栈底Base.

数据结构学习日记(五)_顺序栈

 

 插入元素到栈顶(即表尾)的操作,称为入栈。== PUSH(x)

从栈顶(即表尾)删除最后个元素的操作, 称为出栈。==POP(y)

 

 

LnitStack(&S)初始化操作

操作结果:构造一个空栈S。

 

DestroyStack(&S)销毁栈操作

初始条件:栈S已存在。

操作结果:栈S被销毁。

 

StackEmpty(S)判定S是否为空栈

初始条件:栈S已存在。

操作结果:若栈S为空栈,则返回TRUE,否则FALSE。

 

StackLength(S)求栈的长度

初始条件:栈S已存在。

操作结果:返回S的元素个数,即栈的长度。

 

GetTop(S, &e)取栈顶元素

初始条件:栈S已存在且非空。

操作结果:用e返回S的栈顶元素。

 

ClearStack(&S)栈置空操作

初始条件:栈S已存在。

操作结果:将S清为空栈。

 

Push(&S,e)入栈操作

初始条件:栈S已存在。

操作结果:插入元素e为新的栈顶元素。

 

Pop&S, &e)出栈操作

初始条件:栈S已存在且非空。

操作结果:删除S的栈顶元素an,并用e返回其值。

 

顺序栈的表示和实现

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

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

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

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

数据结构学习日记(五)_链队列_02

 

 

空栈:base == top是栈空标志

栈满:top-base==stacksize

 

 

顺序栈的表示

#define MAXSIZE 100

typedef struct{

  SElemType *base;//栈底指针

  SElemType *top;//栈顶指针

  int stacksize;/栈可用最大容量

}SqStack;

 

顺序栈的初始化

Status lnitStack(SqStack &S){//构造一个空栈

  S.base = new SElemType[MAXSIZE]

  //或S.base=(SElemType*)malloc(MAXSIZE*sizeof(SElemType));

  if(!S.base) exit (OVERFLOW);//存储分配失败

  S.top = S.base; //栈顶指针等 于栈底指针

  S.stacksize = MAXSIZE;

  return OK;

}

 

顺序栈判断栈是否为空

Status StackEmpty(SqStack S){//若栈为空,返回TRUE;否则返回FALSE

  if(S.top == S.base)

    return TURE;

  else

    return FALSE;

}

 

求顺序栈长度

int StackLength(SqStack S){

  return S.top - S.base;

}

 

清空顺序栈

Status ClearStack(SqStack S){

  if(S.base)S.top = S.base;

  return OK;

}

 

销毁顺序栈

Status DestroyStack(SqStack &S){

  if(S.base){
    delete S.base;

    S.stacksize = 0;

    S.base = S.top = NULL;

}

  return OK;

}

 

顺序栈的入栈

(1)判断是否栈满,若满则出错(上溢)

(2)元素e压入栈顶

(3)栈顶指针加1

Status  Push(SqStack &S,sElemType e){

  if(S.top - S.base == S.stacksize)//栈满    

      return ERROR;

  *S.top++ = e;// == *S.top = e;S.top++;

  return OK;

}

 

顺序栈的出栈

(1)判断是否栈空,(若空则出错(下溢)

(2)获取栈顶元素e

(3)栈顶指针减1

Status Pop(SqStack &S,SElemType &e){//若栈不空,则删除S的栈顶元素,用e返回其值/并返回OK;否则返回ERROR

  if(S.top == S.base)//等价于 if(StackEmpty(S))

    return ERROR;

  e = *--S.top;

    return OK;

}

 

链栈是运算受限的单链表,只能在链表头部进行操作

typedef struct StackNode{

  SElemType data;

  struct StackNode *next;

}StackNode, *LinkStack;

LinkStack S;

数据结构学习日记(五)_入栈_03

 

 链表的头指针就是栈顶

不需要头结点

基本不存在栈满的情况

空栈相当于头指针指向空

插入和删除仅在栈顶处执行

 

链栈的初始化

void lnitStack(LinkStack &S){//构造一个空栈,栈顶指针置为空

  S=NULL;

  return OK;

}

 

判断链栈是否为空

Status StackEmpty(LinkStack S)

  if(S == NULL) return TRUE;

  else return FALSE;

}

 

链栈的入栈

Status Push(LinkStack &S,SelemType e){

  p = new StackNode;  //生成新结点p

  p->data = e;  //将新结点数据域置为e

  p->next = S;  //将新结点插入栈顶

  S = p;  //修改栈顶指针

  return OK;

}

 

链栈的出栈

Status Pop(LinkStack &S,ElemType &e){

  if(S == NULL) return ERROR;

  e = S->data;

  p = S;

  S = S->next;

  delete p;

  return OK;

}

 

取栈顶元素

SElemType GetTop(LinkStack S){

  if(S!=NULL)

    return S->data;

}

 

若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的;

若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。

 

分治法求解递归问题算法的一般形式:

void p(参数表){

  if(递归结束条件) 可直接求解步骤;--基本项

  else p(较小的参数);---归纳项

}

 

 

数据结构学习日记(五)_循环队列_04

 

 

 数据结构学习日记(五)_初始化_05

 

 

 

队列(queue)是一种先进先出的线性表。在表一端插入(表尾) ,在另一端(表头)删除

数据结构学习日记(五)_循环队列_06

 

 

 

队列的顺序表示一 用一-维数组base[MAXQSIZE]

#define MAXQSIZE 100//最大队列长度

  Typedef struct{

    QElemType *base;//初始化分配存储空间

    int front;//头指针

    int  rear;//尾指针

}SqQueue;

 

循环队列的操作一队列的初始化

Status lnitQueue(SqQueue &Q){

  Q.base = new QElemType[MAXQSIZE]//分配数组空间

  //Q.base = (QElemType*)

  //malloc(MAXQSIZE*sizeof(QElemType));

  if(!Q.base)  exit(OVERFLOW);

  Q.front = Q.rear =0;  //存储分配失败

  return OK;  //头指针尾指针置为0,队列为空

}

 

循环队列的操作一求队列的长度

int QueueLength(SqQueue Q){

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

 }

 

循环队列的操作一循环队列入队

Status EnQueue(SqQueue &Q,QElemType e){

  if((Q.rear +1)%MAXQSIZE == Q.front) return ERROR;//队满

  Q.base[Q.rear]=e;  //新元素加入队尾

  Q.rear = (Q.rear + 1)%MAXQSIZE;  //队尾指针+1

  return OK;

 

循环队列的操作一循环队列出队

数据结构学习日记(五)_链队列_07

 

 Status EnQueue(SqQueue &Q,QElemType e){

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

  e=Q.base[Q.front];  //保存队头元素

  Q.front = (Q.front+1)%MAXQSIZE://队头指针+1

  return OK;

}

 

循环队列的操作一 取队头元素

SElemType GetHead(SqQuere Q){

  if(Q.front!=Q.rear) //队列不为空

  return Q.base[Q.front];//返回队头指针元素的值,队头指针不变

}

 

若用户无法估计所用队列的长度,则宜采用链队列

数据结构学习日记(五)_顺序栈_08

 

 #define MAXQSIZE 100//最大队列长度

typedef struct Qnode{

  QElemType data;

  stuct Qnode *next;

}QNode,*QuenePtr;

 

链队列的操作一链队列初始化:

Status lnitQueue(LinkQueue &Q){
  Q.front = Q.rear = (QueuePtr) malloc(sizeof(QNode));

  if(!Q.front) exit(OVERFLOW);

  Q.front->next=NULL;

  return OK;

}

 

链队列的操作一销毁链队列

算法思想:从队头结点开始,依次释放所有结点

Status DestroyQueue(LinkQueue&Q){

  while(Q.front){

    p=Q.front->next; free(Q.front); Q.front = p;

}

  return OK;

}

 

链队列的操作一将元素e入队

数据结构学习日记(五)_链队列_09

 

 Status EnQueue(LinkQueue &Q, QElemType e){

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

    if(!p) exit(OVERFLOW);

      p-> data=e; p-> next= NULL;

      Q.rear->next=p;

      Q.rear=p;

      return OK;

}

 

链队列的操作一链队列出队

数据结构学习日记(五)_入栈_10

 

 Status DeQueue (LinkQueue &Q,QElemType &e){

  if(Q.front= =Q.rear) return ERROR;

    p=Q.front-> next;

    e= p->data;

    Q.front-> next= p-> next;

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

    delete p;  

    return OK;

}

 

数据结构学习日记(五)_初始化_11