(三)数据结构——栈,队列和数组

第三章 栈,队列和数组

3.1 栈

3.1.1 栈的基本概念

1.栈的定义

​ 栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。

​ 栈顶:允许进行插入删除的那一端

​ 栈底:固定的,不允许进行插入和删除操作的另一端

​ 空栈:不含任何元素的空表。

​ 栈的操作特性是:先进后出。

2.栈的基本操作

名称详解
InitStack(&S)初始化一个空栈
StacEmpty(S)判断是否为空,若为空则返回true,否则返回false
Push(&S,X)进栈
Pop(&S,&X)出栈
GetTop(S,&x)读取栈顶元素
DestroyStack(&S)销毁栈,并释放栈S占用的存储空间
3.1.2 栈的基本存储结构

​ 栈是一种受限制的线性表,类似于线性表。

​ 1.顺序栈的实现

​ 采用顺序存储的方式进行存储,top指针放在栈顶的位置。

​ 当对栈的的最大使用空间不足时,会发生栈上溢的情况。

​ 栈空条件:S.top == -1,栈满条件:S.top == MaxSize -1 栈长:S.top + 1;

​ 2.顺序栈的基本运算

​ (1)初始化

	void InitStack(SqStack &S){
		S.top = -1;	//初始化栈顶指针
}

​ (2)栈判空

bool StackEmpty(SqStack S){
    if(S.top == -1){
        return true;	//栈空
    }
    else
        return false;	//不空
}

​ (3)进栈

bool Push(SqStack &S,ElemType e){
    if(S.top == Maxsize - 1){	//如果栈满的话就会报错
        rerurn false;
    }
    S.data[++S.top] = X;	//指针先加1,再入栈
    return ture;
}

​ (4)出栈

bool Pop(SqStack &S,ElemType &x){
    if(S.top == -1){	//栈空,则会报错
        return false;
    }
    X = S.data[S.top--];	//先出栈,指针再减1
    return rute;
}

(5)读取栈顶元素

bool GetTop(SqStack S,ElemType &X){
    if(S.top == -1){	//栈空则报错
        return false;
    }
    X = S.data[S.top];	//记录栈顶元素
    return	ture;
}

3.共享栈

​ 共享栈是为了更有效的利用存储空间,两个栈的空间相互调节。只有在整个存储空间被占满时才发生上溢。

3.1.3 栈的链式存储结构

​ 采用链式存储的栈称为链栈。链栈的优点就是多个栈共享存储空间和提高其效率,不存在栈上溢的情况。

3.1.3

3.2 队列

3.2.1 队列的基本概念

​ 1.队列的定义

​ 只下允许在表的一端进行插入,在表的另一端进行删除,插入操作称为入队或进队,删除操作称为出队或离队。

​ 特性:先进先出

​ 队首:允许删除的一端。

​ 队尾:允许插入的一端。

​ 空队列。不含任何元素的空表。

​ 2.队列常见的基本操作

名称详解
InitQueue(&Q)初始化队列,构造一个空队列Q
QueueEmpty(Q)判空:true:false
EnQueue(&Q,x)入队
DeQueue(&Q,&x)出队
GetHead(Q,&x)读取队头
3.2.2 队列的顺序存储结构

1.队列的顺序存储

​ 初始化,栈空条件:Q.front == Q.rear == 0;

​ 先进先出,后进后出

​ 进栈操作:队不满时,先送值到队尾元素,再将队尾指针加1

​ 出栈操作:栈不空时,先取队头元素,再将队头指针加1;

2.循环队列

​ 循环队列相当于一个环状的空间,存储的逻辑上是一个环,称为循环队列,

3.循环队列的操作

​ 初始化:Q.front = Q.rear = 0;

​ 队首指针进1:Q.front = (Q.front + 1) % MaxSize;

​ 队尾指针进1:Q.rear = (Q.rear + 1) % MaxSize;

​ 队列长度:(Q.rear + MaxSize - Q.front)%MaxSize;

​ 出队和入队时,指针都被顺时针方向进1;

​ 判断空的条件:Q.front = Q.rear;

​ 判断队满的条件::Q.front = Q.rear;

​ 由于队空和队满的条件是相同的,因此有一下三种方式进行处理:

​ (1)牺牲一个单元来区分队空和队满,入队时少用一个队列单元,这是一种比较普遍的做法。

​ 队满条件:(Q.rear + 1) % MaxSize == Q.front;

​ 队空条件:Q.front = Q.rear;

​ 队列中存储元素的个数:(Q.rear - Q.front + MaxSize) % MaxSize;

​ (2)类型中增设表示元素个数的数据成员:这样的话队空的条件就是Q.Size == 0;

​ 队满的情况就是:Q.Size ==MxSize;,这两种情况都有Q.front == Q.rear;

​ (3)类型中增设tag数据成员,以区分是队满还是队空。tag等于0时,若因删除导致Q.front == Q.rear,则为队空,若因插入Q.front ==Q.rear,则为队满。

​ 3.循环队列的操作

​ (1)初始化

void InitQueue(SqQueue &Q){
    Q.rear = Q.front = 0;
}

​ (2)判空

bool isEmpty(SqQueue Q){
    if(Q.front = Q.rear;){
       return ture;
    }
	else{
        return false;
    }
}

​ (3)入队

bool EnQueue(SqQueue &Q,ElemType x){
    if((Q.rear + 1) % MaxSize == Q.front){
        return false;
    }
  	Q.data[Q.rear] = x;
    Q.rear = (Q.rear + 1 ) % MaxSize;
    return true;
}

​ (4)出队

bool DeQueue(SqQueue &Q,ElemType x){
    if(Q.rear == Q.front){
        return false;
    }
    X = data[Q.front];
    Q.front = (Q.front + 1) % MaxSize;
    return true;
}
3.2.3 队列的链式存储结构

​ 1.队列的链式存储(带有头节点的)

​ 当Q.front == NULL且Q.rear == NULL时,链式队列为空。

​ 若程序中需要使用多个队列,最好使用链式队列,这样就不会出现存储分配不合理和“溢出”的问题。

​ 链式存储不存在栈满的情况

​ (1)初始化

void InitQueue(LinkQueue &e){
    Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
    Q.front -> NULL;
}

​ (2)判队空

bool isEmpty(LinkQueue Q){
    if(Q.rear == Q.front){
        return falase;
    }
    else{
        rerurn true;
    }
}

​ (3)入队

void EnQueue(LinkQueue &Q,EmemType x){
    LinkNode *S = (LinkNode *)malloc(sizeof(LinkNode));	//初始化
    s -> data = x;
    s -> next = NULL;	//创建新的结点,插入到队尾。
    Q.rear -> next = s;
    Q.rear = s;
}

​ (4)出队

bool DeQueue(LinkQueue &Q,ElemType &x){
    if(Q.rear == Q.front){
        return false;
    }
    LinkNode *p = Q.front -> next;	//P指向队首
    x = p -> date;
    Q.front -> next = p -> next;
    if(Q.rear == p){
        Q.rear == Q.front;	//若原队列中只有一个结点,删除后变空
    }
    free(p);
    return true;
}
3.2.4 双端队列

​ 双端队列是指允许两端都可以进入队和出栈操作的队列/

​ 输出受限的双端队列:允许在一端进行插入和删除,但是在另一端只允许插入的双端队列称为输出受限的双端队列。

​ 输入受限的双端队列:允许在一端进行插入和删除,但是在另一端只允许删除的双端队列称为输入受限的双端队列。

​ 输入是入队,输出是出队。

​ 在栈中合法的输出序列,在双端队列中必定合法。

3.2.5

3.3 栈和队列的应用

3.3.1 栈在括号匹配中的应用

​ 就是括号的匹配问题

3.3.2 栈在表达式求值中的应用

​ 。。。。。。

3.3.3 栈在递归中的应用

​ 递归的次数过多的话容易造成栈的溢出,效率不高的原因是递归调用中包含很多重复的计算。

3.3.4 队列在层次遍历中的应用

​ 应用:二叉树

3.3.5 队列在计算机系统中的应用

​ 应用:缓冲区

3.3.6

3.4 数组和特殊矩阵

3.4.1 数组的定义

​ 数组是由n个相同类型的数据元素构成的有限序列,每个数据称为一个数据元组。

​ 除了结构的初始化和销毁外,数组只会有存储元素和修改元素的操作。

3.4.2 数组的存储结构

​ 对于多维数组,有两种映射方式,按行优先和按列优先,二维数组就是按行优先。

3.4.3 特殊矩阵的压缩存储

​ 1.对称矩阵

​ 对称矩阵存放在一堆数组中[ n ( n + 1 ) / 2 ]:

​ 2.三角矩阵

​ 下三角矩阵压缩存储在[ n ( n + 1 ) / 2 + 1 ];(其中的1是常量的存储)

​ 3.三对角矩阵

​ 对角矩阵又称为带状矩阵。

3.4.4 稀疏矩阵

​ 稀疏矩阵:非零元素远远小于矩阵的个数。

​ 压缩存储策略:三元组存储(每个三元组含有行,列,元素值)

​ 压缩策略二:十字链表法

3.4.5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值