三、栈和队列
栈和队列是两种重要的线性结构。从数据结构的角度来看,栈和队列也是线性表,它的特殊性在于栈和队列的基本操作是线性表操作的子集,它们的操作相对于线性表来说是受到限制的,因此,可以称其为限定性的数据结构。
从数据类型的角度看,它们是和线性表大不相同的两种重要的抽象数据类型,在面向对象的程序设计中,它们是多型数据类型。
3.1-栈
3.1.1-抽象数据类型栈的定义
栈:是限定仅在表尾进行插入或删除操作的线性表,又可以称为后进先出的线性表。
栈顶:栈的表尾端
栈底:栈的表头端
空栈:不含元素的空表
3.1.2-栈的表示和实现
和线性表相似,栈也有两种存储表示方法,即顺序栈和链栈。
(1)栈的顺序存储
所谓栈的顺序存储,就是采用一组物理上连续的存储单元来存放栈中所有元素,并使用top指针来指示当前栈中处于栈顶的元素。
(1.1) 顺序栈的基本操作:
-1:初始化栈函数的实现
- 对栈空间进行初始化
- 对栈顶指针进行初始化
-2:判断栈是否为空的函数实现
- 将当前栈顶指针的值与之前初始化的设置的栈顶指针的值相比较
- 若两者相等,则表示当前栈为空,否则表示当前栈不为空
-3:进栈函数的实现
- 判断当前栈是否有剩余空间
- 若当前栈未满,修改栈顶指针的值,使其指向栈的下一个空闲位置
- 将要进栈的元素放在上述空闲位置,进栈操作完成
- 若栈满则表示没有空间,无法进行栈操作
-4:出栈函数的实现
- 判断栈是否为空,若为空则无法进行出栈操作,给出栈为空的提示
- 若栈不为空,则记下当前栈顶指针的值
- 修改栈顶指针的值,使其指向出栈元素的下一个元素
- 返回第二步中记下的栈顶指针的值对应栈中的元素
-5:获取栈顶元素函数的实现
- 判断当前栈是否为空
- 若当前栈为空,则无法获取任何栈顶元素,词是给出栈为空的提示,并结束操作
- 若不为空,则返回栈顶元素
-6:遍历栈内元素函数的实现
- 判断栈是否为空,若为空,则栈内没有元素可以访问,此时给出栈为空的提示
- 若栈不为空,则从栈底到栈顶依次访问栈中元素
-7:通过用户输入数据的方式创建一个顺序栈
- 接收用户输入
- 若用户输入的是空,则算法结束,否则执行下一步
- 将用户输入的元素进栈
(2)栈的链式存储
栈的顺序存储通常要求系统分配一组连续的存储单元,在实现时,对于某些语言而言,当栈满后想要增加连续的存储空间时无法实现的。我们可以通过链式存储来实现需要多少存储空间就申请多少存储空间,这减低空间使用的浪费率。
(2.1)链栈的基本操作
-1:初始换链栈函数的实现
- 创建一个链栈结点
- 使用该结点对栈顶指针进行初始化
-2:判断链栈是否为空函数的实现
- 判断指示栈顶的结点的指针域是否为空
- 若上一步为真,则表示当前栈为空,否则表示当前栈不为空
-3:进栈函数的实现
- 创建一个新的结点,并将待进栈的元素存入该结点的数据域中
- 将新的结点的指针域指向栈顶结点指针与指向的结点
- 将栈顶结点的指针域指向新的结点
-4:出栈函数的实现
- 判断栈是否为空
- 若第一步为真,则无法执行元素出栈操作,此时给出栈为空的提示,否则执行
- 记下此时的栈顶结点指针域指向的结点
- 修改栈顶结点的指针域,在其中存入第三步记下的结点指针域的值
- 将data域值为da的结点出栈
-5:获取栈顶元素函数的实现
- 判断栈是否为空
- 若第一步为真,则执行第三步,否则执行第四步
- 给出栈为空的提示并返回
- 返回栈顶元素的值
-6:通过用户输入的方式创一个链栈
- 接收用户输入
- 若第一步未结束标志,则算法结束,否则执行下一步
- 将用户输入的元素进栈
3.2-队列
与栈一样,队列也是一种特殊的线性表,不同的是,队列在进行数据操作是必须遵循“先进先出”的原则,这一特点决定了队列的进本操作需要在其两端进行。
3.2.1-队列的基本概念
队列的基本操作通常在队列两端被执行,其中执行插入元素操作的一端被称为队尾;执行删除元素操作的一段被称为队头。队列中的元素个数就是队列的长度,若队列中不包含任何元素,则被称为队空,若队列中没有可用空间存储待进队元素,此时我们称为队满。
3.2.2-队列的顺序存储
队列的顺序存储是指采用一组物理上连续的存储单元来放队列中的所有元素。为了便于计算队列中的元素个数,我们约定,队头指针指向实际队头元素所在位置的前一位置,对位指针指向实际队尾元素所在的位置。
3.2.3-顺序队列的基本操作
(1)初始化队列函数的实现
- 对队列空间进行初始化
- 对队头指针进行初始化
- 对队尾指针进行初始化
(2)判断队列是否为空函数的实现
- 将队头指针的值与队尾指针的值相比较
- 若两者相等则表示当前队列为空,否则表示当前队列不为空
(3)元素进队函数的实现
- 判断当前队列是否有剩余空间
- 若当前队列未满,修改队尾指针的值,使其指向队列的下一个空闲位置
- 将要进对的元素放在上述空闲位置,进队操作完成
- 若队满,则表示没有空间用于执行进队操作
(4)元素出队函数的实现
- 判断队列是否为空,若队空则无法执行出队操作,并提示队列为空
- 若队列不为空,则修改队头指针的值,使其指向待出队元素
- 返回待出队元素
(5)获取队头元素的实现
- 判断当前队列是否为空
- 若第一步为真,则无法获取任何队头元素,此时给出队列为空的提示,并结束操作,否则执行下一步
- 返回当前队头元素
(6)通过用户输入数据的方式创建一个顺序队列
- 接收用户输入
- 若第一步为结束标志,则算法结束;否则执行下一步
- 将用户输入的元素进队
3.2.4-循环顺序队列的基本操作
(1)元素进队函数的实现
- 判断当前队列是否有剩余空间
- 若当前队列未满,则修改队尾指针的值,使其指向队列的下一个空闲位置
- 将要进队的元素放在上述空闲位置,进队操作完成
- 若队满,则表示没有空闲用于执行进队操作
(2)元素出队函数的实现
- 判断队列是否为空
- 若第一步为真,则无法执行出队操作,提示队列为空并返回,否则执行下一步
- 修改队头指针的值使其指向待出队元素
- 返回待出队元素
(3)通过用户输入的方式创建一个循环顺序队列
- 接收用户输入
- 若第一步为结束标志,则算法结束,否则执行下一步
- 将用户输入的数据元素进队
3.2.5-队列的链式存储
1.链式存储的基本操作
(1)创建链式队列函数的实现
- 创建一个新的结点
- 初始化队头指针使其指向新结点
- 初始化队尾指针使其指向新结点
(2)判断队头指针和队尾指针是否为空函数的实现
- 判断队头和队尾指针是否相等
- 若相等则表示当前队列为空,否则表示当前队列不为空
(3)进队函数的实现
- 创建一个新的结点,并将待进队的元素存入该结点的数据域中
- 将结点的地址存入队尾指针指向的结点的指针域中
- 将队尾指针指向新结点
(4)出对函数的实现
- 判断队列是否为空,若队列为空,则无法执行出队操作,此时给出队列为空的提示,否则执行下一步
- 鸡下队头指针指向的结点的下一个结点
- 修改队头指针指向的结点的指针域,在其中存入第二步中记下结点的指针域的值
- 判断队尾指针所在结点是否相等域第二部中记下的结点
- 若第四步为真,则修改队尾指针,将其指向队头指针指向的结点
- 返回出对元素
(5)获取队头元素函数的实现
- 判断队列是否为空
- 若第一步为真,则无法获取队头元素,提示队列为空,并结束操作;否则执行下一步
- 返回队头元素的值
(6)通过用户输入数据的方式创建一个队列
- 接收用户的输入
- 若第一步为结束标志,则算法结束,否则执行下一步
- 将用户输入的数据元素进队。
2.循环链式队列
循环链式队列是将链式队列的队尾指针所在的结点指向头结点。由于头结点的下一个结点就是队头元素所在得到位置,而队尾指针所在的结点又指向头结点,所以由队尾指针也可以找到队头元素,因此在循环链式队列中我们不需要再增设队头指针。
3.3-递归
3.3.1-什么是递归
递归是数学中一个十分重要的概念,它也被大量应用在计算技术中,其特征为直接或间接调用自身,我们通常把一函数调用自身称为递归,否则称为间接递归。在算法设计中,任何间接递归都可以转化为直接递归来实现。