开始复习专业课了,慢慢来。
Stack
栈,这种表的特点是先进后出,课本上很形象的一幅图是叠盘子,先放的盘子是最后被取出来的。
栈中元素的插入和删除都是在栈顶进行的,而表的另一端就是栈底。
主要成员函数:push(const stack_entry &num) 将元素num推入栈中,放在栈顶,栈顶指针加一。
pop() 将栈顶元素弹出栈,具体实现是通过将栈顶指针减一。
top(stack_entry &num) const 将栈顶元素赋值给num,但并不弹出栈。(这里必须用形参,实参是传不回去的。。。)
clear() 将栈清空
empty() const 检测栈是否为空,为const类型,不可随意更改
数据成员; stack_entry entry[n] 在此通过数组来实现栈; 由于声明的数组类型,所以n必须声明为const变量
count 栈中元素个数,利用count-1记录栈顶
在栈的实现中,利用泛型将栈用于许多不同的应用中,给起赋予不同的值类型,同时利用枚举变量作为stack类的方法的返回类型,便于返回错误信息。
Queue
队列,这种表的特点是先进先出(first in first out,即FIFO),就像排队买票一样,排在前面的人永远先买到票。
队列有队头和队尾,先进先出则是利用这两个指针实现的,即在队头进行删除操作,在队尾进行插入操作。
主要成员函数:append(queue_entry &num)将元素num推入队列中,放在队尾,队尾指针加1
serve() 将队头元素弹出队,将队头指针减一
retrieve(queue_entry &num) const 将队头元素赋值给元素num
其他函数与stack类似
数据成员:queue_entry entry[n] 在此同样通过数组来实现队列
count 队列元素个数,通过count是否为0来判断队列是否为空
front,rear 队头队尾指针
注:
为了减少队列删除元素的复杂度,通常使用循环队列,即删除一个元素时只改变front指针,不移动其后的所有元素,而当队尾指针或者队头指针等于数组容量时则置零,实现循环队列。
循环队列会引起如何判断队列为空的问题,如果使用front和rear指针的位置判断队列为空,则会发现当队列为空和队列为满时,rear指针都在front指针的前一个位置
(队列为满时rear必然在front前一个位置;当队列只有一个元素时,删除该元素,rear指针不变,front指针加1,则出现了与队列为满时的情况)
所以需要一种判断队列是否为空的方法,除了通过count来判断队列中元素个数的方法之外(个人认为最简单)还有很多方法,例如
1. 在队头和队尾中保留一个空位,在队尾出现在队头前两个位置时则判断队列为满
2. 增加一个布尔变量,当加入一个元素使rear指针正好在front指针前一个位置时用来指示队列为满
3. 将front或rear设置为特定的值来表示队列为空或为满的情况(与第二种方法类似)
总的来说,stack和queue除了数据处理的方式上有点区别,实现上是类似的,都是基本的数据结构,面试题中也常有利用queue实现stack,或用stack实现queue的方法。
网上通常有两种方法可以实现:
1. 入队时直接压入栈1即可;出队时则将栈1中的元素逐个导入栈2中,栈2中的栈顶便类似于queue的队头,进行插入操作
2. 入队时判断栈1是否为空,若不为空,证明元素在栈1中,则可以进行入队操作,否则将元素先从栈2移入栈1再进行操作;
同理,出队时则判断栈2是否为空,若不为空,则可以进行出队操作,否则将元素从栈1移入栈2再进行操作。
第二种方法将第一种方法进行了优化,减少了不必要的移动。总的来说,stack和queue是基础啊~~~