《数据结构与算法(Python语言描述)》第三章LList1链表实现

这里主要记录我的实现过程中的思考和遇到的错误


书上介绍了设计LList1链表时,需要怎么去考虑,首先可以先画出要实现的大致功能和思路:

《数据结构与算法(Python语言描述)》第三章LList1链表实现_第1张图片

然后根据书里的模式,建立了ADT模型:

ADT LList1(LList)
    LList1(self)                  # 初始化结点指针
    prepend(self, elem)           # 根据elem创建新结点,并插入到首端
    append(self, elem)            # 根据elem创建新结点,并插入到尾端
    inster_add(self, elem, i)     # 根据elem创建新结点,并插入到下标i所指示的位置
    pop(self)                     # 删除首端结点,并返回结点值
    pop_last(self)                # 删除尾端结点,并返回结点值
    inster_pop(self, i)           # 删除下标i所指定的结点,并返回结点值

根据书上说的,我们需要考虑每个变化操作在首端时候如何运行、尾端时如何运行、还有一般情况时如何运行。

书上要求给出返回表长度的方法,可以用一个计数器_len来实现,每增加一个结点就+1,删除一个结点就-1
然后就要考虑这个计数器放置在哪里,我们想要的是每个LList1都有自己的结点计数器,互相之间不干扰,那么我们就将它设置为实例变量,并在初始化函数__init__(self)中将其置零self._len = 0,我将它设置到LList类,这样每一个从LList派生的类都可以使用这个计数器.

对于inster_add方法:

#将新创建的节点插入到指定的 i 处
#   1、空表插入或者下标为首节点时,调用prepend方法
#   2、i > 表长时,将节点尾端插入,调用append方法
#   3、i 在表长范围之内时,循环找到下标为 i-1
#   的节点,改变其next,使之链接更新为新节点,新节点next指向
def inster_add(self, elem, i):
    if self._head is None or i == 0:
        return self.prepend(elem)

    if i >= self._len: #    i 超出下标范围;
        return self.append(elem)

    else:
        n = 0
        p = self._head
        while n < (i - 1): # 取下标为i结点的前一个结点
            p = p.next
            n += 1
        p.next = LNode(elem, p.next)
        self._linkedlistlen(1)

当添加的是首端元素时,我们直接调用prepend方法,好处在于不用重复的写一样的代码,而且当我们改变首端元素的表现形式时,直接修改prepend方法就可以了,方便维护;尾端元素也是同理。
请注意一下上面的return self.prepend(elem)return self.append(elem),最开始我写的是self.prepend(elem),这样就产生了一个问题
我希望判断首端元素添加完成之后,直接退出整个函数,但程序流程执行完prepend(self, elem)方法后,会继续运行剩下的程序,导致最终又执行了eles块内的程序,一个元素会被插入两遍,self._rear指向第一次插入的元素,并没有更新。

解决问题的方式是,在每个判断里增加return
例如:return self.prepend(elem)

下面是全部代码:

class LList1(LList):
     def __init__(self):
         LList.__init__(self)
         self._reat = None # 尾指针设置为None

     #根据下标值 i 返回节点下标为 i 的值; 超出范围返回尾节点的值
     def inster_print(self, i):
         if self._head is None:
             return None
         if i > (self._len - 1):
             return self._reat.elem
         n = 0 #记录循环次数,即下标
         p = self._head
         while n != i:
             p = p.next
             n += 1
         return p.elem

     #在前端插入节点时,需要考虑表为空的插入情况。
     def prepend(self, elem):
         if self._head is None:
             self._head = LNode(elem)
             self._reat = self._head
             self._linkedlistlen(1)
         else:
             self._head = LNode(elem, self._head)
             self._linkedlistlen(1)

     #在表尾插入节点时,需要更新self._reat;还要考虑表空时候如何插入。
     def append(self, elem):
         if self._head is None: # 当表为空时
             self._head = LNode(elem, self._head)
             self._reat = self._head #头尾指针指向同一个节点
             self._linkedlistlen(1)
         else:
             self._reat.next = LNode(elem)
             self._reat = self._reat.next
             self._linkedlistlen(1)

     #将新创建的节点插入到指定的 i 处
     #   1、空表插入或者下标为首节点时,调用prepend方法
     #   2、i > 表长时,将节点尾端插入,调用append方法
     #   3、i 在表长范围之内时,循环找到下标为 i-1
     #   的节点,改变其next,使之链接更新为新节点,新节点next指向
     def inster_add(self, elem, i):
         if self._head is None or i == 0:
             return self.prepend(elem)
         if i >= self._len: #    i 超出下标范围
             return self.append(elem)
         else:
             n = 0
             p = self._head
             while n < (i - 1): # 取下标为i结点的前一个结点
                 p = p.next
                 n += 1
             p.next = LNode(elem, p.next)
             self._linkedlistlen(1)

     #pop操作后,如果表为空,将尾指针设置为None,避免inster_print调用尾指针
     def pop(self):
         e = LList.pop(self)
         if self._head is None:
             self._reat = self._head
         return e

     #删除尾节点。考虑删除尾节点时候需要更新self._reat;删除节点为最后一个节点时,需要将self._head指向None。
     def pop_last(self):
         if self._head is None:
             raise LinkedListUnderflow("in pop_last")
         p = self._head
         if p.next is None:
             e = p.elem
             self._head = None
             self._reat = None #当表为空时,将尾指针设置为None,以支inster      _print方法
             self._linkedlistlen(-1)
             return e
         while p.next.next is not None:
             p = p.next
         e = p.next.elem
         p.next = None
         self._reat = p
         self._linkedlistlen(-1)
         return e

     #删除下标为 i 的节点
     #1、考虑表为空时,抛出异常
     #2、i 超出下标范围时,抛出index异常
     #3、i 为首、尾下标时,调用已有方法
     #4、正常情况时候,首、尾指针不改变
     def inster_pop(self, i):
         if self._head is None:
             raise LinkedListUnderflow("in pop_inster")
         if i > (self._len - 1):
             raise LinkedListIndex("index error")
         elif i == 0:
             return self.pop()
         elif i == (self._len - 1):
             return self.pop_last()
         else:
             p = self._head
             n = 1 # 下标
             while n < i: #循环,直到得到下标节点的前一个节点
                p = p.next
                n += 1
             e = p.next.elem
             p.next = p.next.next
             self._linkedlistlen(-1)
             return e 
 class LinkedListUnderflow(ValueError):
     pass

 class LinkedListIndex(IndexError):
     pass

那么,就这样,欢迎指正,谢谢!
《数据结构与算法(Python语言描述)》第三章LList1链表实现_第2张图片

你可能感兴趣的:(学习)