数据结构学习 --3 栈,队列和数组

数据结构学习 --1 绪论
数据结构学习 --2 线性表
数据结构学习 --3 栈,队列和数组
数据结构学习 --4 串
数据结构学习 --5 树和二叉树
数据结构学习 --6 图
数据结构学习 --7 查找
数据结构学习 --8 排序

本人学习记录使用 希望对大家帮助 不当之处希望大家帮忙纠正

数据结构学习 --3 栈,队列和数组



在这里插入图片描述

3.1 栈

3.1.1 栈的基本概念

1.栈的定义

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

栈顶(Top)。线性表允许进行插入删除的那一端。 栈底(Bottom)。固定的,不允许进行插入和删除的另一端。

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

假设某个栈S=(al,a2,a3,a4,a5),则a1为底元素,a5为顶元素。由于栈只能在栈顶进行插入和删除操作,进栈次序依次为a1,a2,a3,a4,a5,而出栈次序为a5,a4,a3,a2,a1由此可见,栈的操作特性可以明显地概括为后进先出(Last In FirstOut,LIFO)。

2.栈的基本操作

InitStack(&S) #  初始化一个空栈
StackEmpty(S)# 判断一个栈是否为空,若栈为S 为空则返回true,否则返回false
Push(&S,x) # 进栈,若栈 s 未满,则将x加入使之成为新栈顶。
Pop(&S,&x) # 出栈,若栈S非空,则弹出栈顶元素,并用x返回
GetTop(S,&x) # 读栈顶元素,若栈s 非空,则用x 返回栈顶元素
DestroyStack(&S) # 销毁栈,并释放栈S 占用的存储空间 (&”表示引用调用)

3.1.2 栈的顺序存储结构

栈是一种操作受限的线性表,类似于线性表,它也有对应的两种存储方式。
1.顺序栈的实现
采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元’同时附设一个指针 (top)指示当前栈顶元素的位置。

栈顶指针:s.top,初始时设置 s.top=-1;找顶元素:S.data[s.top]。
进栈操作:栈不满时,栈顶指针先加 1,再送值到栈顶元素。
出栈操作:栈非空时,先取栈顶元素值,再将栈顶指针减 1。
栈空条件: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 x){
	if(S.top == MaxSize-1)  //栈满,报错
		return false;
	S.data[++S.top] =x; //指针先加1,在入栈
	return true; 
}

(4)出栈

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

(5)读栈顶元素

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

3.1.3 栈的链式存储结构

采取链式存储的栈为链栈,链栈的优点是方便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的,这里规定链栈没有头结点,Lhead指向栈顶元素。

3.2 队列

3.2.1 队列的基本概念

  1. 队列的定义
    队列(Queue)简称队,也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。向队列中插入元素称为入队或进队;删除元素称为出队或离队。这和我们日常生活中,最早排队的也是最早离队的,其操作的特性是先进先出(First In First Out,FIFO),
    队头 (Front)。允许删除的一端,又称队首。
    队尾(Rear)。允许插入的一端。
    空队列。不含任何元素的空表。

  2. 队列常见的基本操作

InitQueue(&Q):初始化队列,构造一个空队列 Q。
QueueEmpty(Q):判队列空,若队列Q为空返回 true,否则返回 
falseEnQueue(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回。
GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给 x。

需要注意的是,栈和队列是操作受限的线性表,因此不是任何对线性表的操作都可以作为栈和队列的操作。比如,不可以随便读取栈或队列中间的某个数据。

3.2.2 队列的顺序存储结构

  1. 队列的顺序存储
    队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置(不同教材对front和rear的定义可能不同,例如,可以让 rear 指向队尾元素、front 指向队头元素。对于不同的定义,出队入队的操作是不同的
    初始时:Q.front=Q.rear=0。
    进队操作:队不满时,先送值到队尾元素,再将队尾指针加1出队操作:队不空时,先取队头元素值,再将队头指针加 1。

  2. 循环队列
    将顺序队列臆造为一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。当队首指针Q.front=Maxsize-1后,再前进一个位置就自动到 0,这可以利用除法取余运算 (%)来实现。
    初始时:Q.front=Q.rear=0a
    队首指针进1:Q.front=(Q.front+1)%MaxSize。
    队尾指针进1:Q.rear=(Q.rear+1)%MaxSize。
    队列长度:(Q.rear+MaxSize-Q.front)%MaxSize

那么,队空的条件是 Q.front ==Q.rear若入队元素的速度快于出队元素的速度,则队尾指针很快就会赶上队首指针,
为了区分是队空还是队满的情况,有三种处理方式:

(1)牺牲一个单元来区分队空和队满,入队时少用一个队列单元,这是一种较为普遍的做法;
队满条件:(Q.rear+1)%MaxSize == Q.fronte
队空条件:Q.front==Q.rear。
队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize

(2)类型中增设表示元素个数的数据成员。这样,
队空的条件为Q.size0;
队满的条件为Q.size
MaxSize。
这两种情况都有 Q.front==Q.rear

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

  1. 循环队列的操作
    (1)初始化
void InitQueue(SqQueue &Q){
	Q.rear=Q.front=0; //初始化队首、队尾指针
}

(2)判断队列为空

bool isEmpty(SqQueue Q){
	if(Q.rear==Q.front)   //队空条件
		return true;
	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.rearm =(Q.rear+1)%MaxSize;//队尾指针加1取模
	return true; 
}

(4)出队

bool DeQueue(SqQueue &Q,ElemType &x){
	if(Q.rear==Q.front) return false; //队空则报错
	x=Q.data[Q.front];
	Q.front=(Q.front+1)%MaxSizer;  //队头指针加1取模
	return true;
}

3.2.4 双端队列

双端队列是指允许两端都可以进行入队和出队操作

3.3 栈和队列的应用

3.3.1 栈在括号匹配中的应用

假设达式中允许包含两种括号:括号号其的即([([][)等均为正确的格式,[(])或([()(()的格式考虑下列括号序列:

在这里插入图片描述

分析如下:
(1)计算机接收第1个括号“[”后,期待与之配的第8个括号“]”出现。
(2)获得了第2个括号“(”第1个号“”在一边而急期与配的7个号“)”出现。
(3)得了第3个括号“[”,此时第2个号“(”时在一边而急期待与之配的第4个括号“]”出现。第3个括号的期待得到满足,消解之后,第2个括号的期待匹配又成为当前最急追的任务。
(4)以此类推,可见该处理过程与的思想吻合算法的思想如下:
(4-1)初始设置一个空,顺序读入括号。
(4-2)若是右括号,则或使置于顶的最急迫期待得以消解,或是不合法的况(括号序列不匹配,退出程序)。
(4-3)若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消3解的期待的急迫性降了一级。算法结束时,栈为空,否则括号序列不匹配。

3.3.2 在表达式求值中的应用

表达式求值是程序设计语言编译中一个最基本的问题,它的实现是栈应用的一个典型范例中缀表达式不仅依赖运算符的优先级,而且还要处理括号。后缀表达式的运算符在操作数后面,在后缀表达式中已考虑了运算符的优先级,没有括号,只有操作数和运算符。

3.3.3 栈在递归中的应用

递归是一种重要的程序设计方法。简单地说,若在一个函数、过程或数据结构的定义中又应
用了它自身,则这个函数、过程或数据结构称为是递归定义的,简称递归。它通常把一个大型的复杂问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的代码就可以描述出解题过程所需要的多次重复计算,大大减少了程序的代码量。
但在通常情况下,它的效率并不是太高。

int Fib(int n){
	//斐波那契数列的实现
	if(n==0) return 0; //边界条件
	else if(n==1) return 1; //边界条件
	e1se return Fib(n-l)+Fib(n-2); //递归表达式
}

必须注意递归模型不能是循环定义的,其必须满足下面的两个条件递归表达式《递归体)。
边界条件(递归出口)。
递归的精髓在于能否将原始问题转换为属性相同但规模较小的问题。在递归调用的过程中,系统为每一层的返回点、局部变量、传入实参等开辟了递归工作栈来进行数据存储,递归次数过多容易造成栈溢出等。而其效率不高的原因是递归调用过程中包含很多重复的计算

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

在信息处理中有一大类问题需要逐层或逐行处理。这类问题的解决方法往往是在处理当前层或当前行时就对下一层或下一行做预处理,把处理顺序安排好,等到当前层或当前行处理完毕,就可以处理下一层或下一行。使用队列是为了保存下一步的处理顺序。

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

队列在计算机系统中的应用非常广泛,以下仅从两个方面来简述队列在计算机系统中的作用:第一个方面是解决主机与外部设备之间速度不匹配的问题,第二个方面是解决由多用户引起的资源竞争问题。

对于第一个方面,仅以主机和打印机之间速度不匹配的问题为例做简要说明。主机输出数据给打印机打印,输出数据的速度比打印数据的速度要快得多,由于速度不匹配,若直接把输出的数据送给打印机打印显然是不行的。解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入这个缓冲区,写满后就暂停输出,转去做其他的事情。打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求。主机接到请求后再向缓冲区写入打印数据。这样做既保证了打印数据的正确,又使主机提高了效率。由此可见,打印数据缓
冲区中所存储的数据就是一个队列。

对于第二个方面,CPU(即中央处理器,它包括运算器和控制器)资源的竞争就是一个典型的例子。在一个带有多终端的计算机系统上,有多个用户需要
CPU各自运行自己的程序,它们分别通过各自的终端向操作系统提出占用CPU
的请求操作系统通常按照每个请求在时间上的先后顺序,把它们排成一个队列,每次把
CPU分配给队首请求的用户使用。当相应的程序运行结束或用完规定的时间间隔后,令其出队,再把 CPU
分配给新的队首请求的用户使用。这样既能满足每个用户的请求,又使 CPU 能够正常运行。

3.4 数组和特殊矩阵

矩阵在计算机图形学、工程计算中占有举足轻重的地位。在数据结构中考虑的是如何用最小的内存空间来存储同样的一组数据。所以,我们不研究矩阵及其运算等,而把精力放在如何将矩阵更有效地存储在内存中,并能方便地提取矩阵中的元素。

3.4.1 数组的定义

数组是由n(n>1)个相同类型的数据元素构成的有限序列,每个数据元素称为一个数组元素,每个元素在n个线性关系中的序号称为该元素的下标,下标的取值范围称为数组的维界。

数组与线性表的关系:数组是线性表的推广。一维数组可视为一个线性表:二维数组可视为其元素也是定长线性表的线性表,以此类推。数组一旦被定义,其维数和维界就不再改变。因此,除结构的初始化和销毁外,数组只会有存取元素和修改元素的操作。

3.4.2 数组的存储结构

大多数计算机语言都提供了数组数据类型,逻辑意义上的数组可采用计算机语言中的数组数据类型进行存储,一个数组的所有元素在内存中占用一段连续的存储空间。

对于多维数组,有两种映射方法:
按行优先和列优先。以二维数组为例,按行优先存储的基本思想是:先行后列,先存储行号较小的元素,行号相等先存储列号较小的元素。

3.4.3 特殊矩阵的压缩存储

压缩存储:指为多个值相同的元素只分配一个存储空间,对零元素不分配存储空间。其目的是节省存储空间。

特殊矩阵:指具有许多相同矩阵元素或零元素,并且这些相同矩阵元素或零元素的分布有一定规律性的矩阵。常见的特殊矩阵有对称矩阵、上(下)三角矩阵、对角矩阵等。特殊矩阵的压缩存储方法:找出特殊矩阵中值相同的矩阵元素的分布规律,把那些星现规律性分布的、值相同的多个矩阵元素压缩存储到一个存储空间中。

  1. 对称矩阵
    如图:在这里插入图片描述

  2. 三角矩阵
    在这里插入图片描述

  3. 三对角矩阵
    在这里插入图片描述

3.4.4 稀疏矩阵

矩阵中非零元素的个数1,相对矩阵元素的个数s 来说非常少即st的阵称为疏阵例如,一个矩阵的阶为100x100,该矩阵中只有少于100
个非零元素。若采用常规的方法存储稀疏矩阵,则相当浪费存储空间,因此仅存储非零元素。但通常非零元素的分布没有规律,所以仅存储非零元素的值是不够的,还要存储它所在的行和列。因此,将非零元素及其相应的行和列构成一个三元组(行标,列标,值)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小*-^-*九

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值