《数据结构与算法(Python语言描述)》第三章LCList表部分功能实现

实现书中给出的几个功能,方便对照书籍发现自己的错误


书上实现了大概以下几个功能

prepend功能:建立新结点,并插入到首端。
append功能 :建立新结点,并插入到尾端。
pop功能 :前端弹出。
printall功能:输出表元素。

首先建立ADT模型,把要实现的功能和大概用到的数据写出来,整理下思路,下面是建立ADT模型之前的考虑
需不需要从我们实现过的链表类中派生LCList类?
可以发现,重复用到的只有尾指针self._rear,和计数器self._len,其他的方
法都需要覆盖重写,那么就不需要从其他链表类中派生。

下面是用XMind做的,类似于ADT模型
LCList


下面我们按着书中实现的顺序对比我自己写的功能进行分析(略过一目了然的功能)。

我是实现的prepend功能

def prepend(self, elem):
    if self._rear is None: #表是空滴
        p = LNode(elem) # 建立新结点
        self._rear = p # 更新尾结点
        p.next = p # 将结点next域指向寄己
        self._len += 1
    else:
        p = self._rear # p 为尾结点
        p.next = LNode(elem, p.next)
        self._len += 1

书上实现的prepend功能

def prepend(self, elem):
    p = LNode(elem) # 将重复建立结点的语句抽出来
    if self._rear is None:
        p.next = p # 建立一个结点的环,结点的next域指向寄己
        self._rear = p
        self._len += 1 # 计数器,__init__中创建
    else:
        p.next = self._rear.next #新建结点的next域,指向原来的首端结点
        self._rear.next = p
        self._len += 1

我实现的append功能

def append(self, elem):
    if self._rear is None:
        self.prepend(elem) # 这里这么写,是因为空表添加的代码与prepend方法空表添加时,是一样的
    else:
        p = self._rear
        p.next = LNode(elem, p.next)
        self._rear = p.next # 更新尾结点,哪个是尾结点,self._rear说了算
        self._len += 1

前方高能!!!

书上实现的append功能

def append(self, elem):
    self.prepend(elem)
    self._rear = self._rear.next

很简洁有没有,我想过这么写,但有点担心给别人看的话可能不那么直观;现在看来,只需要模拟一下整个流程,完全可以搞懂的。
这里看一下书中91页的说明:

由于循环链表里的结点连成一个圈,哪个结点算是表头或表尾,主要是概念问题,从表的内部形态上无法区分

表中唯一辨识尾结点的就是尾指针self._rear,而无论是将结点插入表头还是表尾,过程完全是一样的,区别仅仅在于self._rear的指向,它指谁,谁就是表尾,所以完全可以将插入结点部分交给prepend方法来做,append方法只需要修改self._rear指向。

跳过pop功能,比较简单,当然我实现的比书上罗嗦点。
我实现的printall功能

def printall(self):
    if self._rear is None:
        return None
    p = self._rear.next # 首端结点赋值给变量P
    end = self._rear # end为尾端结点
    while p is not end: # 当p 是尾端结点时,结束循环
        print(p.elem, end="")
        p = p.next
    print(p.elem)

比较罗嗦,如果别人读这样的代码可能就要花点时间理顺。
书上实现的printall功能

def printall(self):
    if self.is_empty():
        return
    p = self._rear.next # 首结点
    while True:
        print(p.elem)
        if p is self._rear: # 如果 p 是最后的结点
            break # break直接结束循环
        p = p.next

将 p 设置为尾结点也可以,改动判断条件就行了。

总结

我们看一下这里的思想:

面向对象编程具有封装性:实现与调用分离,无论内部怎么实现,只要满足功能,提供调用的接口就可以。


那么,就这样,欢迎指正和提问,谢谢!
马克思主义乖巧

猜你喜欢

转载自blog.csdn.net/qq_39672528/article/details/79839543