上次文章中提到几个习题,这里解决一下:
R-6.3 实现一个函数transfer(S,T)将栈S中所有元素倒置放入T。
def transfer(S, T): while not S.is_empty(): T.push(S.pop())还有其他解法,比较简单。
C-6.16 修改栈的实现方法,加入一个参数maxlen,使其大小限制在maxlen中,若超出,则抛出一个异常。
我的想法是在__init__中添加一个self._maxlen和self._size,每次push前先判断max和len的大小,在进行压栈操作。
class ArrayStack: DEFAULT_len = 10 def __init__(self): self._data = [] self._maxlen = ArrayStack.DEFAULT_len self._size = 0 def push(self, val): if self._maxlen <= self._size self._data.append(val) self._size += 1同样地,在pop时进行一次self._size的自减。
抛出异常的话,就不赘述了,定义一个异常类,raise即可。
C-6.18 实现R-6.3功能使其在原栈上更改输出。
我不知道这道题的正确解决思路是什么,我觉得会不会是加一个中间变量而已?希望大家能提出自己的想法。
def transfer2(S): temp = [] size = 0 while not S.is_empty(): temp.append(S.pop()) size += 1 for i in range(size): S.push(temp[i])感觉中间有很多过程可以省略,水平有限,就这样吧。
P-6.35 栈常用于“撤销”操作,在上面的练习中我们做了一个栈满抛出异常的练习,现在尝试模拟我们真实的“撤销”操作,即撤销的历史记录是有一个上限的,我们在达到上限(maxlen)时,将最底下的元素抛弃掉,来腾出空间。
下面考虑三种思路,第一种也是最直观的,即抛弃掉第一个元素,然后后面的元素依次迭代回来,我们需要一个扔掉栈底的函数,就叫他dump吧。
def dump(self): del(self._data[0]) self._size -= 1简单粗暴,必定带来问题,就是列表元素确实是删除了,但是其实在python内部进行了一次迭代,算法的时间复杂度是O(n),当元素数量一旦上来了,所消耗的时间是线性增长的。
这里考虑第二种思路,就是我给这个栈一个顶和底的属性,这个顶和底实际上是一种索引,顶索引到我应该压栈到哪个位置的值、底索引到我该抛弃掉哪个位置的值,这个思路非常简单。但是唯一的缺点就是更像是对列表进行操作而削弱了栈的压入、弹出操作,各有千秋。
最后一种思路,是链表,一旦考虑到列表的扩大、缩小,一定少不了操作上更好实现的链表,用链表实现这个问题会在后期链表种讲到。
明天开始学习队列、双端队列,道理和栈差不多。
