栈的定义:
栈是限定仅在表尾**(栈顶)进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称后进先出的线性表(LIFO)**。
栈的插入操作:叫做进栈,也称为压栈,入栈。
栈的删除操作:也叫出栈
进栈出栈变化形式:
栈对线性表的插入和删除的位置进行了限制,并没有对元素进出的时间进行限制,也就是说,不是所有元素都进栈的情况下,事先进去的元素也可以出栈,只要保证是栈顶的元素出栈就可以。
栈的抽象数据类型:
栈本身是一个线性表,所有线性表的顺序存储和链式存储对栈来说,也是同样适用的。
栈的顺序存储结构:
简称为顺序栈。以下标为0的一端作为栈底。定义top变量来表示栈顶元素在数组中的位置。若栈的长度为stacksize,则栈顶位置top必须小于stacksize。当栈中存在一个元素时,top=0;空栈的定义为top= -1;
栈的顺序存储结构——进栈操作
栈的顺序存储结构——出栈操作
栈的链式存储结构及实现:
简称:链栈。栈是栈顶来做插入删除数据的,栈顶放在单链表的头部。
栈的链式存储结构——进栈操作
假设元素值为e的新结点是s,top为栈顶指针。进栈操作:
栈的链式存储结构——出栈操作
(1) 假设变量p用来存储要删除的栈顶结点;
(2) 将栈顶指针指向下移一位;
(3) 释放p
栈的应用——递归:
递归:把一个直接调用自己或者通过一系列的调用语句间接的调用自己的函数,称为递归函数。
每个递归定义必须至少有一个条件,满足递归条件不再进行,即不再引用自身而是返回值退出。
迭代和递归的区别:迭代使用的是循环结构,递归使用的是选择结构。递归调用会建立函数的副本,会消耗大量时间和内存。迭代不需要反复调用函数。
队列:
队列的定义:
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先进先出(FIFO)的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。
队列的抽象数据类型
同样是线性表,队列也有类似线性表的各种操作,不同的就是插入数据只能在队尾,删除数据在队头。
队列的顺序存储结构:
假设一个队列有n个元素,则顺序存储的队列需要建立一个大于n的数组,数组下标为0的一端是队头,所谓入队操作就是在队尾增加一个元素,不需要移动任何元素,时间复杂度为O(1)。与栈不同,队列出队元素在队头,出队时,队列中的所有元素都要向前移动,要保证队头,即数组下标为0的位置不能为空。所以时间复杂度为O(n)。这样出队没有性能。
改变出队的性能:
删除元素front加1,插入元素加1,front最开始指向队头的前一个位置。Rear是指向元素真实的地址。 Front = rear 空队列;
假溢出:
再入队,数组末尾已经占用,再向后加,就会产生数组越界的错误。但是数组前面的内存是空的。这种现象称为“假溢出”。
循环队列的定义:
为了解决假溢出的问题,引入循环队列。
把队列的头尾相接的顺序存储结构称为循环队列。
(1) 解决方案:
方法一:设置一个标志位flag,当front == rear,且flag = 0时,队列为空。当front == rear,且flag =1时,队列为满。
方法二:队列为空时front == rear。队列满时,修改条件,保留一个元素空间,换句话说,队列满时,数组中还有一个空闲单元。
队列顺序存储结构的操作
队列的链式存储结构及实现:
队列的链式存储结构,实际上就是线性表的单链表,只不过它只能尾进头出。简称链队列。队头指针指向链对列的头结点,队尾指针指向终端结点。
空队列时,front和rear都指向头结点。
队列的链式存储结构——入队操作:
入队操作时,其实就是在链表的尾部插入结点。
(1) 把拥有元素e的新结点s赋值给原队尾结点的后继。
(2) 把当前s设置为队尾的结点,rear指向s。
队列的链式存储结构——出队操作:
头结点的后继结点出队,将头结点的后继该成它后面的结点。若链表除了头结点外只剩下一个元素时,则需要将rear指向头结点。队列为空。