数据结构是计算机存储、组织数据的方式。
栈,队列,都是数据结构的一种。在程序的设计过程中,对某些数据的存储使用栈或者队列,可以提高程序的运行效率。
栈,也称为堆栈。它的特点是,后进先出。每一次你只能对最后被放入堆栈的数据来进行操作。就像是没开封的一筒羽毛球,每一次都必须先拿出最顶层的球。存入数据的操作一般被称为“push”,而取出数据的操作一般被称为“pop”。
图1-堆栈
队列。它的特点是,先进先出。每一次你只能对最早被放入队列的数据进行操作。就像是游乐场的推币机,每一次被推走的都是最早被投进去的硬币。存入数据的操作被称为“push”,而取出数据的操作被称为“pop”。
图2-队列
实际应用
堆栈和队列都是人为设置的一种数据存储结构。根据不同的程序设计需求而使用堆栈或队列来处理数据。
比如,当用户打开了浏览器,这一次使用时所有访问过的网址都会被存在一个堆栈中,这样当用户点击“后退”按钮时,直接对堆栈进行pop操作,就可以得到前一个访问地址。
或者,医院或者银行的取号等待系统,所有被领取的号码都会被存在一个队列中,这样每当一个用户被接待完毕,直接对队列进行pop操作,就可以得到下一个被接待人的号码。
使用C语言来实现栈和队列的结构
前面提到,栈和队列都是人为设置的。在C语言中,为了实现栈和队列的结构,我们使用的更基本的数据结构是数组和链表。
在介绍他们的顺序和链式结构之前,我们先了解一下何为顺序结构,链式结构。
①链表存储结构的内存地址不一定是连续的,但顺序存储结构的内存地址一定是连续的;
②链式存储适用于在较频繁地插入、删除、更新元素时,而顺序存储结构适用于频繁查询时使用。
栈的顺序式存储结构
我们可以使用数组结构来构造一个顺序栈。
图-顺序栈
假设我们使用C语言构造一个容量为6的栈。我们初始化一个长度为6的数组,六个元素对应的下标依次为0,1,2,3,4,5。我们设计一个参数top,用它来记录栈顶。当栈内没有数据的时候,栈为空,top记为-1。当栈内数据已满,top的值为5.对数据进行push操作,就是把数据存到数组内 top+1 的位置,执行完之后top++,这样top记录的就是新的栈顶位置。对数据进行pop操作,就是读取数组内 top-1 的位置的数据,执行完之后top--,记录新的栈顶位置。
队列的顺序式存储结构
我们也可以使用数组来构造一个栈结构。
图-顺序队列
假设我们使用C语言构造一个容量为5的队列。我们初始化一个长度为5的数组,六个元素的下标依次为0,1,2,3,4。我们设计两个参数,front:队头,rear:队尾。当 front==rear 时,队列为空。当 rear==5 时,队列已满。 在这个例子中,front永远被标记为0。对数据进行push操作,就是将数据存储在数组内 rear 的位置,然后rear++,来标记新的队尾。对数据进行pop操作,就是读取数组内 front 位置的数据,而后将数组内所有其他数据的下标前移一个位置,rear--。在这里你可能会发现,这样的处理方式对系统的开销很大,主要是因为将所有数据前移一个位置的这一步操作。所以在这个基础上我们有循环队列。
图-顺序队列(循环)
在前一个顺序队列的基础上,进行pop操作时,我们读取数组内 front 位置的数据,然后将front++。进行push操作时,我们将数据存在数组内 rear 位置上,而后让 rear = (rear+1) % length,length是数组的长度,即 rear+1 对 length 取模。此时,当rear = front,队列为空。当 front = (rear+1)%length,队列已满。
栈与队列的链式存储结构
栈与队列的链式存储结构的思路与顺序存储结构是相同的,只是在实现时,我们使用链表来进行实现。而上文中的 front,rear 也被指针变量所表示。