数据结构4(第三章)

听王卓老师的《数据结构》的课做的笔记

1️⃣2️⃣3️⃣4️⃣5️⃣🎉🪂🐟🐋🐳🍎🍇🍉

3.1栈和队列的定义和特点

3.1.1总起

栈和队列是两种常用的、重要的数据结构

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

栈和队列是线性表的子集(是插入和删除位置受限的线性表)

普通线性表的插入和删除操作

栈的应用

队列的常见应用

3.1.2栈的定义和特点

1️⃣栈的定义

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

"又称为后进先出(Last In First Out)的线性表,简称LIFO结构,

2️⃣栈的相关概念

3️⃣栈的示意图

4️⃣思考题

5️⃣总结

3.1.3队列的定义和特点

定义

队列的相关概念

3.2案例引入

案例3.2.1 进制转换

案例3.2.2括号匹配的检验

案例3.2.3 表达式求值

3.2.4舞伴问题

3.3栈的表示和操作的实现

1️⃣2️⃣3️⃣4️⃣5️⃣🎉🪂🐟🐋🐳🍎🍇🍉

3.3.1栈的抽象数据类型的类型定义

3.3.2栈的表示和实现

由于栈本身就是线性表,于是栈也有顺序存储和链式存储两种实现方式。

栈的顺序存储---顺序栈

栈的链式存储---链栈

1️⃣顺序栈的表示和实现

1. 🐳存储方式:同一般线性表的顺序存储结构完全相同。

1.利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。

2.栈底一般在低地址端。

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

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

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

2. 🐳使用数组作为顺序栈存储方式的特点:

简单、方便、但易产生溢出(数组大小固定)

上溢(bverflow): 栈已经满,又要压入元素

下溢(underflow): 栈已经空,还要弹出元素

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

3. 🐳顺序栈的表示
#define MAXSIZE 100
typedef struct{
    SElemType*base; //栈底指针
    SElemType*top; //栈顶指针
    int stacksize;//栈可用最大容量
}SqStack;

4. 算法3.1 顺序栈的初始化

Status InitStack(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;
}

5. 【算法补充】顺序栈判断栈是否为空

Status StackEmpty(SqStack S) {
    //若栈为空,返回TRUE;否则返回FALSE
    if (S.top == S.base)
        return TRUE;
    else
        return FALSE;
}

6. 【算法补充】求顺序栈长度

int StackLength( SqStack S)
{
   return S.top- S.base;
}

7.【算法补充】清空顺序栈

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

8.【算法补充】销毁顺序栈

Status DestroyStack( SqStack &S ){
    if( S.base ){
    delete S.base;//回归内存池
    S.stacksize = 0;
    S.base = S.top = NULL;
    }
return OK;
}
9.算法3.2 顺序栈的入栈

算法3.3 顺序栈的出栈

3.3.3链栈的表示和实现

2️⃣链栈的表示

算法3.5 :链栈的初始化
void lnitStack(LinkStack &S ){
    //构造一个空栈,栈顶指针置为空
    S=NULL;
  return OK;
}
补充算法:判断链栈是否为空
Status StackEmpty(LinkStack S)
    if(S==NULL) 
    return TRUE;
    else return FALSE;
}
算法3.6 链栈的入栈

Status Push(LinkStack &S , SElemType e){
    p=new StackNode;//生成新结点p
    p->data=e: //将新结点数据域置为e
    p->next=S;//将新结点插入栈顶
    S=p;//修改栈顶指针
return OK;
}
算法3.7 链栈的出栈

Status Pop (LinkStack &S,SElemType &e){
    if (S==NULL) return ERROR;
    e= S-> data;
    p = S:
    S= S-> next;
    delete p;
    return OK;
}
算法3.8 取栈顶元素

SElemType GetTop(LinkStack S) {
    if (S!=NULL)
    return S->data;
}

3.4栈与递归1️⃣2️⃣3️⃣4️⃣5️⃣

🐋递归的定义

🐋用到递归情况的3种方法

1️⃣递归定义的数学函数

2️⃣递归性质的数据结构

3️⃣可递归求解的问题

🐋递归问题---用分治法解决

🍎定义

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

🍎函数调用过程

🍎多个函数构成嵌套调用

🍎求解阶乘n!的过程

🍎递归函数调用的实现

🍎进行fact(4)调用的系统栈的变化状态

🍎递归的优缺点

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

3.5队列的表示和操作的实现

3.5.1队列的介绍

队列示意图

相关术语

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

表尾即

端,称为队尾;表头即

端,称为队头。

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

插入元素称为入队;删除元素称为出队

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

队列的相关概念

队列的常见应用

3.5.2队列的抽象数据类型定义

3.5.3队列的顺序表示和实现

队列的物理存储可以用顺序存储结构,也可用链式存储结构。

队列的存储方式也分为两种,即顺序队列和链式队列。

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

#define MAXQSIZE 100 //最大队列长度
Typedef struct {
    QElemType *base;//初始化的动态分配存储空间
    //这个数组是qelemtype类型
    //队列中每一个存储元素都用一个数组
    //指针指向数组首元素
    int front;//头指针
    int rear;//尾指针
}sqQueue;

解决假上溢的方法

循环队列的类型定义

循环队列的操作---队列的初始化(算法3.11)

Status initQueue (SqQueue &Q){
    Q.base =new QElemType[MAXQSIZE]//分配数组空间
    //Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
        if(!Q.base) exit(OVERFLOW);//存储分配失败
    Q.front=Q.rear=0;//头指针尾指针置为0,队列为空
    return OK;
}

循环队列的操作---求队列的长度(算法3.12)

循环队列的操作---循环队列入队(算法3.13)

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

循环队列的操作---循环队列出队(算法3.14)

循环队列:循环使用为队列分配的存储空间

Status DeQueue (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;
}

循环队列的操作---取对头元素(算法3.15)

SElemType GetHead(SqQuere Q){
    if(Q.front!=Q.rear)//队列不为空
        return Q.base[Q.front];//返回队头指针元素的值,队头指针不变

3.5.4链队--队列的链式表示和实现

链队列的类型定义

#define MAXQSIZE 100 //最大队列长度
typedef struct Qnode {
    QElemType data;
    stuct Qnode *next;
}QNode, *QuenePtr;
typedef struct {
    QuenePtr front; // 队头指针
    QuenePtr rear; // 队尾指针
} LinkQueue;

链队列运算指针变化状况

链队列的操作---链队列初始化(算法3.16)

Status InitQueue (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;
    }//Q.rear=Q.front->next; free(Q.front); Q.front=Q.rear;
return OK;
}

链队列的操作--将元素e入队(算法3.17)

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;

链队列的操作--链队列出列(算法3.18)

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

链队列的操作--求链队列的队头元素(算法3.19)

头结点的下一个结点

Status GetHead (LinkQueue Q, QElemType &e){
  if(Q.front==Q.rear) return ERROR;
  e=Q.front->next->data;
  return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值