王道数据结构第三章笔记

这篇笔记详细介绍了栈和队列的概念及其各种实现方式,包括顺序栈、链栈、共享栈、顺序队列、链队列和双端队列。还探讨了括号匹配和表达式求值问题,以及二维数组的存储结构,如特殊矩阵的压缩存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第三章

栈与队列

栈的定义

(线性表的具有相同数据类型的n个数据元素的有序有限序列,其中n为表长,当n=0时,线性表为空表)

是只允许一端插入或删除的 线性表

n个不同元素进栈,出栈元素不同排列个数为:

1n+1\dfrac{1}{n+1}n+11*C(22n)C\binom{2}{2n}C(2n2)

顺序栈
定义

(用顺序存储方式实现的栈)

#define MaxSize 10
typedef struct {
    Elemtype data[MaxSize];
    int top;//栈顶指针,存放栈顶元素的下标
}SqStack;
初始化操作
//第一种初始化S.top = -1;
#define MaxSize 10
typedef struct {
    Elemtype data[MaxSize];
    int top;//栈顶指针,存放栈顶元素的下标
}SqStack;
void InitStack(SqStack &S) {
    S.top = -1;//初始化栈顶指针
}
//第二种初始化S.top = 0;
#define MaxSize 10
typedef struct {
    Elemtype data[MaxSize];
    int top;//栈顶指针,存放栈顶元素的下标
}SqStack;
void InitStack(SqStack &S) {
    S.top = 0;//初始化栈顶指针
}
进栈
//第一种的进栈
bool Push(Sqtack &S, Elemtype x) {
    if(S.top == MaxSize - 1) {
        return false;
    }
    S.top = S.top + 1;
    S.data[S.top] = x;
    return true;
}
//第二种的进栈
bool Push(Sqtack &S, Elemtype x) {
    if(S.top == MaxSize - 1) {
        return false;
    }
    S.data[S.top] = x;
    S.top = S.top + 1;
    return true;
}
出栈
//第一种的出栈
bool Pop(Sqtack &S, Elemtype &x) {
    if(S.top == -1) {
        return false;
    }
    x = S.data[S.top];
    S.top = S.top - 1;
    return true;
}
//第二种的出栈
bool Pop(Sqtack &S, Elemtype &x) {
    if(S.top == 0) {
        return false;
    }
    x = S.data[S.top-1];
    S.top = S.top - 1;
    return true;
}
读栈顶元素
//第一种读栈顶元素
bool GetTop(SqStack &S, Elemtype &x) {
    if(S.top == -1) {
        return false;
    }
    x = S.data[top];
    return true;
}
//第二种读栈顶元素
bool GetTop(SqStack &S, Elemtype &x) {
    if(S.top == 0) {
        return false;
    }
    x = S.data[top-1];
    return true;
}
共享栈

两个栈共享一个存储空间,有两个栈顶指针,分别存放顺序表的第一个元素前一个的下标比如-1,和存放顺序表最后一个元素下标的后一个比如MaxSize

定义
#define MaxSize 10
typedef struct {
    Elemtype data[MaxSize];
    int top0;//0号栈顶指针,存放栈顶元素的下标
    int top1;//1号栈顶指针,存放栈顶元素的下标
}ShqStack;
初始化操作
#define MaxSize 10
typedef struct {
    Elemtype data[MaxSize];
    int top0;//0号栈顶指针,存放栈顶元素的下标
    int top1;//1号栈顶指针,存放栈顶元素的下标
}ShqStack;

void InitShStack(ShStack &S) {
    S.top0 = -1;
    S.top1 = Maxsize;
}

栈满的条件

top0 + 1 == top1
链栈
定义

用链式存储方式实现的栈

image-20210515155139825

创建(初始化)
//不带带头结点的
typedef struct LSNode {
    Elemtyoe data;
    struct LSNode *next;
}LSNode, *LinkStack;
bool InitLStack(LinkStack &LS) {
    LS = NULL;//空表,暂时没有任何节点,防止脏数据
    return true;
}
void test() {
    LinkStack LS;
    initLStack(L);
}
//带头结点的
typedef struct LSNode {
    Elemtyoe data;
    struct LSNode *next;
}LSNode, *LinkStack;
bool InitLStack(LinkStack &LS) {
    LS = (LSNode *)malloc(sizeof(LSNode));//分配一个头结点
    if(LS == NULL) {//内存分配不足,分配失败
        return false;
    }
    LS = NULL;//空表,暂时没有任何节点,防止脏数据
    return true;
}
void test() {
    LinkStack LS;
    initLStack(L);
}
增(进栈)

这里可以用到头插法

//带头结点的
bool pop(LinkStack &LS,Elemtype e) {//将值为e的节点插入栈中
    LSNode s = (LSNode *)malloc(sizeof(LSNode));
    LSNode *p = LS;//p用于指向头结点
    s->data = e;
    s->next = p = next;
    p->next = s;
    return true;
}
//不带头结点
bool pop(LinkStack &LS,Elemtype e) {//将值为e的节点插入栈中
    LSNode s = (LSNode *)malloc(sizeof(LSNode));
    LSNode *p = LS;
    s->data = e;
    if(LS == NULL) {//空表的时后直接往里头加就行
        LS = s;
    }else {
        s->next = p->next;
        p->next = s;
    }
    return true;
}
删(出栈)
//带头结点的
bool push(LinkStack &LS,Elemtype &e) {//将出栈的元素值放入e中
    if(LS->next == NULL) {//判断表空
        return false;
    }
    LSNode *p = LS;//p指向栈头结点
    LSNode *q = p->next;//q指向头结点的下一个结点,也就是要出栈的栈顶元素
   	e = p->next->data;//将栈顶的值放入e中
    p->next = q->next;
    free(q);
    return true;
}
//不带头结点的
bool push(LinkStack &LS,Elemtype &e) {//将出栈的元素值放入e中
    if(LS == NULL) {//判断表空
        return false;
    }
    LSNode *p = LS;//指向栈顶结点,就是栈顶元素
    e = p->data;
    LS = LS->next;//栈顶指针直接指向下一个元素
    free(p);//释放之前栈顶的结点
    return true;
}
查(获取栈顶元素)
//带头结点的
bool Top(LinkStack &LS,Elemtype &e) {//将出栈的元素值放入e中
    if(LS->next == NULL) {//判断表空
        return false;
    }
    LSNode *p = LS;//p指向栈头结点
    e = p->next->data;//将栈顶元素的值存放在e中
    return true;
}
//不带头结点的
int Top(LinkStack &LS,Elemtype &e) {//将出栈的元素值放入e中
    if(LS == NULL) {//判断表空
        return false;
    }
    LSNode *p = LS;//p指向栈头结点
    e = p->data;//将栈顶元素的值存放在e中
    return true;
}
判断表空
//带头结点的
bool juiceEmpty(LinkStack &LS) {
    if(LS->next == NULL) {
        return true;
    }
}
//不带头结点的
bool juiceEmpty(LinkStack &LS) {
    if(LS == NULL) {
        return true;
    }
}
队列
定义

只允许在一端进行插入,在另一端进行删除的 线性表,先进先出

(线性表时具有相同数据类型的n(n>=0)个数据元素的有限序列,其中n为表长,但n=0时相信表为一个空表。

image-20210515173905617

image-20210515174049269

image-20210515174221614

顺序队列
#define MaxSize 10
typedef struct{
    ElemType data[MaxSize];//用静态数组存放
    int front, rear;//队头指针和队尾指针
}SqQueue;
初始化操作

队尾指针指向队尾元素后一个元素

#define MaxSize 10
typedef struct{
    ElemType data[MaxSize];//用静态数组存放
    int front, rear;//队头指针和队尾指针
}SqQueue;
void InitQueue(SqQueue &Q) {
    Q.rear = Q.front = 0;//初始化队头指针指向0
}
void testQueue() {
    //申明一个顺序队列
    SqQueue Q;
    InitQueue(Q);
    //...后续操作...
}

队尾指针指向队尾元素

#define MaxSize 10
typedef struct{
    ElemType data[MaxSize];//用静态数组存放
    int front, rear;//队头指针和队尾指针
}SqQueue;
void InitQueue(SqQueue &Q) {
    Q.front = 0;//初始化队头指针指向0
    Q.rear = MaxSize - 1;
}
void testQueue() {
    //申明一个顺序队列
    SqQueue Q;
    InitQueue(Q);
    //...后续操作...
}
入队

队尾指针指向队尾元素后一个元素

bool EnQueue(SqQueue &Q,ElemType x) {
    if((Q.rear+1)%MaxSize == Q.front){//判断队满,这时牺牲一个出差空间来进行判断队满
        return false;
    }
    Q.data[Q.rear] = x;//将x插入队列
    Q.rear = (Q.rear+1)%MaxSize;//队尾指针往后移,并取模
}

image-20210515180431227

队尾指针指向队尾元素

bool EnQueue(SqQueue &Q,ElemType x) {
    if((Q.rear+2)%MaxSize == Q.front){//判断队满,这时牺牲一个出差空间来进行判断队满
        return false;
    }  
    Q.rear = (Q.rear+1) % MaxSize;//队尾指针往后移,并取模
    Q.data[Q.rear] = x;//将x插入队列
}
出队

队尾指针指向队尾元素后一个元素

//删除一个队头元素,并用x返回
bool DeQueue(SqQueue &Q,ElemType &x) {
    if(Q.rear == Q.front) {//判断队空
        return false;
    }
    x = Q.data[Q.front];
    Q.front = (Q.front+1)%MaxSize;//队头指针往后移动,并取模
    return true;
}

队尾指针指向队尾元素

//删除一个队头元素,并用x返回
bool DeQueue(SqQueue &Q,ElemType &x) {
    if((Q.rear+1)%MaxSize == Q.front) {//判断队空
        return false;
    }
    x = Q.data[Q.front];
    Q.front = (Q.front+1)%MaxSize;//队头指针往后移动,并取模
    return true;
}

(获得队头元素)

队尾指针指向队尾元素后一个元素

bool GetHead(SqQueue Q,ElemType &x) {
    if(Q.rear == Q.front){//判断队空
        return false;
    }
    x = Q.data[Q.front];
    return true;
}

队尾指针指向队尾元素

bool GetHead(SqQueue Q,ElemType &x) {
    if((Q.rear+1)%MaxSize == Q.front){//判断队空
        return false;
    }
    x = Q.data[Q.front];
    return true;
}
队中元素数量
(rear+MaxSize-front) % MaxSize//稍微修改也可以进行判断空与满
判断队满/空方案二

(不浪费任何元素)

#define MaxSize 10
typedef struct {
    ElemType data[MaxSize];
    int front,rear;
    int size;//队列当前长度
}SqQueue;

image-20210515182538635

(rear+MaxSize-front) % MaxSize//稍微修改也可以进行判断空与满
判断队满/空方案三
#define MaxSize 10
typedef struct {
    ElemType data[MaxSize];
    int front,rear;
    int tag;//最近进行的时删除/插入
}SqQueue;

image-20210515182703302

链队列
定义
typedef struct LinkNode{//链式队列结点
    ElemType data;
    struct LinkNode *next;
}LinkNode;
typedef struct{//链式队列
    LinkNode *front,*rear;//队列的头指针和尾指针
}LinkQueue;
初始化
//带头结点的
void InitQueue(LinkQueue &Q) {
    //初始化front,rear都指向头结点
    Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));//申请一个头结点
    Q.front->next = NULL;
}
void testLinkQueue() {
    LinkQueue Q;//声明一个队列
    InitQueue(Q);//初始化队列
    //...后续操作...
}
//不带头结点
void InitQueue(LinkQueue &Q) {
    //初始时front,rear都指向NULL
    Q.front = NULL;
    Q.rear = NULL;
}
判空
//带头结点的
bool IsEmpty(LinkQueue Q) {
    if(Q.front == Q.rear) {
        return true;
    }else {
        return false;
    }
}
//不带头结点的
bool IsEmpty(LinkQueue Q) {
    if(Q.front == NULL) {
        return true;
    }else {
        return false;
    }
}
入队
//带头结点的
void EnQueue(LinkQueue &Q,ElemType x) {
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;//不要忘了
    Q.rear->next = s;//新结点插入到rear之后
    Q.rear = s;//修改表尾指针
}
//不带头结点的
void EnQueue(LinkQueue &Q,ElemType x) {
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = x;
    s->next = NULL;
    if(Q.front == NULL) {//在空队列中插入第一个元素
        Q.front = s;//修改队头指针
        Q.rear = s;//修改队尾指针
    }else {
        Q.rear->next = s;//新结点插入到rear之后
    	Q.rear = s;//修改表尾指针
    } 
}
出队

image-20210515193819902

//带头结点的
bool DeQueue(LinkQueue &Q,Elemtype &x) {
    if(Q.front == Q.rear) {//表空判断
        return false;
    }
    LinkNode *p = Q.front->next;
    x = p->data;
    if(Q.rear == p){//此次时最后一个结点出队
        Q.rear = Q.front;//修改rear的指针
    }
    free(p);//释放空间
    return true;       
}

image-20210515195225087

//不带头结点的
bool DeQueue(LinkQueue &Q,Elemtype &x) {
    if(Q.front == NULL) {//表空判断
        return false;
    }
    LinkNode *p = Q.front;
    x = p->data;
    if(Q.rear == Q.front){//此次时最后一个结点出队
        Q.rear = Q.front = NULL;//修改front和rear的指针
    }
    Q.front = p->next;
    free(p);//释放空间
    return true;       
}
双端队列

image-20210516185523377

考点:判断元素输出序列合法性(eg:4个有序序列)

  • 双端队列:image-20210516191337563

  • 栈的出栈序列:image-20210516191509701

  • 输入受限制的双端队列:

image-20210516191637242

  • 输出受限的双端队列:

image-20210516210801879

括号匹配问题

image-20210529101715429

bool bracketCheck(char str[], int length) {
    SqStack S;
    InitStack(S);//初始化一个栈
    for(int i = 0;i < length; i++) {//左括号入栈
        if(str[i] == '(' || str[i] == '[' || str[i] == '{') {
            push(S, str[i]);
        }else {
            if(StackEmpty(S)){//扫描右括号,且当前栈空
                renturn fasle;//匹配失败
            }
            char topElem;
            Pop(S, topElem);//栈顶元素弹出
            if(str[i] == ')' && topElem != '('){
                return false;
            }
            if(str[i] == ']' && topElem != '['){
                return false;
            }
             if(str[i] == '}' && topElem != '{'){
                return false;
            }
        }
    }
    return StackEmpty(S);//检索全部括号后,栈空说明匹配成功
}
表达式求值问题

image-20210529104419597

  • 后缀表达式

    左优先原则

    注意:操作数是有左右顺序

    image-20210529102807892

    转化为算法主要思想:

    image-20210529104744033

  • 前缀表达式

    右优先原则

    注意:操作数是有左右顺序

image-20210529104039994

image-20210529104222008

二维数组的存储结构
  • 行优先

image-20210529112037801

  • 列优先

    image-20210529112137872

  • 对称矩阵

    image-20210529112401339

  • 三角矩阵

image-20210529113019979

  • 对角矩阵的压缩存储

image-20210529113353063

image-20210529122815954

image-20210529122917028

  • 稀疏矩阵

image-20210529123047476

image-20210529123127305

特殊矩阵总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值