栈和队列的定义和实现(详细)

栈和队列的定义和实现

栈和队列的定义和特点

  • 栈和队列是限定插入和删除只能在表的“端点”进行的线性表
  • 是线性表的特殊情况

  • 栈的示意图

栈和队列的定义和实现(详细)_第1张图片

  • 栈的应用

数值转换、表达式求值
括号匹配、八皇后问题
行编译程序、函数调用
迷宫问题、递归调用的实现


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

  • 栈的相关概念
    1.定义:限定只能在表的一端进行插入和删除运算的线性表(只能在栈顶操作)
    2.逻辑结构:与线性表相同,仍为一对一关系。
    3.存储结构:用顺序栈戟链栈存储均可,但以顺序栈更常见
    4.运算规则:只能在栈顶运算,且访问结点时依照进先出(LIFO)的原则
    5.实现方式:关键是编写入栈和出栈函数,具体实现依顺序栈或链栈的不同而不同
    6.插入和删除都在一端进行,进行插入和删除操作的一端叫栈顶,另一端叫栈底

  • 栈的特点
    后进先出

  • 栈与一般线性表用什么不同

栈和队列的定义和实现(详细)_第2张图片

队列

  • 队列的示意图

栈和队列的定义和实现(详细)_第3张图片

  • 队列的应用

    • 脱机打印输出:按申请的先后顺序依次输出。
    • 多用户系统中,多个用户排成队,分时地循环使用CPU和主存
    • 按用户的优先级排成多个队,每个优先级一个队列
    • 实时控制系统中,信号按接收的先后顺序依次处理
    • 网络电文传输,按到达的时间先后顺序依次进行

  • 队列的定义
    插入在线性表的一端(表尾),删除在表的另一端(表头)

  • 队列的相关概念
    1.定义:只能在表的一端进行插入运算,在表的另一端进行删除运算的线性表(头删尾插)
    2.逻辑结构:与线性表相同,仍为一对一关系
    3.存储结构:顺序队或链队,以循环顺序队列更常见
    4.运算规则:只能在队首和队尾运算,且访问结点时依照先进先出(FIFO)的原则
    5.实现方式:关键是掌握入队和出队操作,具体实现依顺序队或链队的不同而不同

  • 栈的特点
    先进先出

栈和队列的实现

顺序栈表示和实现
  • 存储方式:同一般线性表的顺序存储结构完全相同

栈和队列的定义和实现(详细)_第4张图片


  • 栈满栈空标志

栈和队列的定义和实现(详细)_第5张图片


  • 栈满时的处理方法:
    1、报错返回操作系统。
    2、分配更大的空间,作为栈的存储空间将
    原栈的内容移入新栈。

  • 使用数组作为顺序栈存储方式的特点:
    简单、方便、但易产生溢出(数组大小固定)
    上溢( overflow)):栈已经满,又要压入元素
    下溢( underflow)):栈已经空,还要弹出元素

注:上溢是一种错误,使问题的处理无法进行;而溢般认为是
一种结束条件,即问题处理结束。

  • 顺序栈的表示
#define MAXSIZE 100
typedef struct{
  SElemType *base;// 栈底指针
  SElemType *top;// 栈顶指针
  int stacksize;// 栈的最大个数
}SqStack;
  • 顺序栈的初始化
Status InitStack(SqStack &S){
  S.base=new SElemType[MAXSIZE];// 初始化空间
  if(!S.base)exit(OVERFLOW);
  S.top=S.base;// 建立空栈
  S.stacksize=MAXSIZE;
  return OK;
}
  • 判断顺序栈是否为空
Status StackEmpty(SqStack S){
  if(S.top==S.base)return TRUE;
  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)元素压入栈顶
    (3)栈顶指针加1
Status Push(SqStack &S,SElemType e){
  if(S.top-S.base==S.MAXSIZE)return ERROR;// 判断是否栈满
  *S.top++=e;//加入新元素
  return OK;
}
  • 顺序栈的出栈
    (1)判断是否栈空,若空则出错
    (2)获取栈顶元素e
    (3)栈顶指针减1
Status Pop(SqStack &S,SElemType &e){
  if(S.top==S.base)return ERROR;//判断栈是否为空
  e=*--S.top;//取栈顶元素
  return OK;
}
链栈的表示
  • 链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct StackNode{
  SElemType data;
  struct StackNode *next;
}StackNode,*LinkStack;
LinkStack S;
  • 链栈的存储

栈和队列的定义和实现(详细)_第6张图片

  • 注:
    1.链表的头指针就是栈顶
    2.不需要头结点
    3.基本不存在栈满的情况
    4.空栈相当于头指针指向空
    5.插入和删除仅在栈顶处执

  • 链栈的初始化

void InitStack(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->data=S;
  p->next=S;
  S=p;//栈顶
  return OK;
}
  • 链栈的出栈
Status Pop(LinkStack &S,SElemType &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;
}
栈与递归
  • 递归的定义

    • 若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的;
    • 若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。
      例如:递归求n的阶乘

  • 以下三种情况常常用到递归方法

    • 递归定义的数学函数(阶乘函数、斐波那契数列)
    • 具有递归特性的数据结构(二叉树、广义表)
    • 可递归求解的问题(迷宫问题、Hanoi塔问题)

  • 递归问题-用分治法求解

    • 分治法:对于一个较为复杂的问题,能够分解成几个相对简单的且解法
      相同或类似的子问题来求解
    • 必备的三个条件
      • 1、能将一个问题转变成一个新问题,而新题与原问题的解法相同
        或类同,不同的仅是处理的对象,且这些处理对象是变化有规律的
      • 2、可以通过上述转化而使问题简化
      • 3、必须有一个明确的递归出口,或称递归的边界
  • 分治法求解递归问题算法的一般形式:

void p(参数表){
  if(递归结束条件) 可直接求解; ---基本项
  else p(较小的参数); ---归纳项
}

eg:

long Fact(long n){
  if(n==0)return 1;//基本项
  else return n*Fact(n-1);//归纳项
}

  • 函数调用过程
    • 调用前,系统完成:
      • (1)将实参返回地址等传递给被调用函数
      • (2)为被调用函数的局部变量分配存储区
      • (3)将控制转移到被调用函数的入口
    • 调用后系统完成
      • (1)保存被调用函数的计算结果
      • (2)释放被调用函数的数据区
      • (3)依照被调用函数保存的返回地址将控制转移到调用函数

  • 多个函数嵌套调用:

栈和队列的定义和实现(详细)_第7张图片


  • 递归的优缺点
    • 优点:结构清晰,程序易读
    • 缺点:每次调用要生成工作记录,保存状态信,入栈;返回时要出栈恢复状态信息。时间开销大。

  • 递归->非递归实现
    方法1:尾递归、单向递归→循环结构
    方法2:自用栈模拟系统的运行时栈

  • 尾递归->循环结构

栈和队列的定义和实现(详细)_第8张图片

  • 单线递归->循环结构

栈和队列的定义和实现(详细)_第9张图片
栈和队列的定义和实现(详细)_第10张图片

  • 借助栈改写递归(了解)

栈和队列的定义和实现(详细)_第11张图片

  • 借助栈改写递归方法(了解)

栈和队列的定义和实现(详细)_第12张图片

队列

  • 队列的相关术语

栈和队列的定义和实现(详细)_第13张图片

队列的顺序表示
  • 队列的类型定义
#define MAXQSIZE 100
typedef struct {
  QElemType *base;//初始化动态存储空间
  int front,rear;//对头和对尾
}SqQueue;
  • 队列的操作
    初始化:front=rear=0;
    入队:base[rear]=x,rear++;
    出队:x=base[front],front++;
    队空标志:front==rear;

  • 解决假溢出的方法–引入循环队列
    取余实现

  • 循环队列队满对空判断
    1.另设一个标志以区别对空队满
    2.另设一个变量,记录元素的个数
    3.少用一个元素***

  • 少用一个元素空间判断队空队满
    队满:(rear+1)%maxsize == front
    队空:rear == front

  • 队列初始化

Status InitQueue(SqQueue &Q){
  Q.base=new QElemType[MAXQSIZE];//分配数组空间
  if(!Q.base)exit(OVERFLOW);//分配失败
  Q.front = Q.rear = 0;
  return 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;
  return OK;
}
  • 循环队列出队
Status DeQueue(SqQueue &Q,QElemType &e){
  if(Q.front==Q.rear)return ERROR;
  e=Q.base[Q.front];
  Q.front=(Q.front+1)%MAXQSIZE;
  return OK;
}
  • 取队头元素
SElemType GetHead(SqQueue Q){
  if(Q.front!=Q.rear)
    return Q.base[Q.front];
}
队列的链式存储
  • 链队列的类型定义
#define MAXQSIZE 100
typedef struct QNode{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;

typedef struct{
  QueuePtr front;
  QueuePtr rear;
}LinkQueue;
  • 链队列的指针变化
    尾插头删

  • 链队列的初始化

Status InitQueue(LineQueue &Q){
  Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
  if(!Q.front)exit(OVERFLOW);
  Q.front->next=NULL;
  return OK;
}
  • 链队列的销毁
Status DestroyQueue(LinkQueue &Q){
  LinkQueue p;
  while(Q.front){
    p=Q.front->next;free(Q.front);Q.front=p;
  }
  return OK;
}
  • 链队列的入队
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;
}
  • 链队列的出队
Status 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;
  delete p;
  return OK;
}
  • 链队列的对头元素
Status GetHead(LinkQueue Q,QElemType &e){
  if(Q.front==Q.rear)return ERROR;
  e=Q.front->next->data;
  return OK;
}

你可能感兴趣的:(数据结构,c++,数据结构)