Python 单向链接表反转与排序

《数据结构与算法:Python 语言描述》(裘宗燕 著)讲解链表的过程清楚明了,反转的算法也很高效,没有使用回归。但是有两处笔误:

  • 第95页,单链表反转, ._next 应该改为 .next
  • 第98页,单链表调整链接法排序,小循环有错误。

裘宗燕教授在“数据结构与算法(Python 语言)”教学材料中列明了新的示例代码,如果发现书中代码有问题,可以直接查看网页上的新代码。

1 单链表反转

唯一就是有一处笔误。
3.4.4 两个链表操作/链表反转 书中代码是:

def rev(self):
    p = None
    while self._head is not None:
        q = self._head
        self._head = q.next # 摘下原来的原结点
        q._next = p 
        p = q               # 将刚摘下的结点加入 p 引用的结点序列
    self._head = p          # 反转后的结点序列已经做好,重置表头链接

其中倒数第三行的 ._next 应该改为 .next,因为结点类 LNode 中类属性是.next

        q.next = p

如果把其中的 p 变量更名为 tmp_list_head,把 q 改为 sliced_node可能更能理解。

完整的程序,包括测试如下:

# coding:utf8

class LinkedListUnderflow(ValueError):
    pass

class LNode(object):
    def __init__(self, elem, next_=None):
        self.elem = elem
        self.next = next_

class LList(object):
    def __init__(self):
        self._head = None
    
    def is_empty(self):
        return self._head is None

    def prepend(self, elem):
        self._head = LNode(elem, self._head)

    def pop(self):
        if self._head is None:
            raise LinkedListUnderflow("in pop")
        e = self._head.elem
        self._head = self._head.next
        return e

    def append(self, elem):
        if self._head is None:
            self._head = LNode(elem)
            return
        p = self._head
        while p.next is not None:
            p = p.next
        p.next = LNode(elem)

    def pop_last(self):
        if self._head is None:
            raise LinkedListUnderflow
        p = self._head
        if p.next is None:
            e = p.elem
            self._head = None
            return e
        while p.next.next is not None:
            p = p.next
        e = p.next.elem
        p.next = None
        return e

    def rev(self):
        tmp_list_head = None
        while self._head is not None:
            sliced_node = self._head
            self._head = self._head.next
            sliced_node.next = tmp_list_head
            tmp_list_head = sliced_node 
        self._head = tmp_list_head

    def elements(self):
        p = self._head
        while p is not None:
            yield p.elem
            p = p.next

    
def main():
    lst = LList()
    for i in range(10):
        lst.append(i)
    print "original linked list:"
    for i in lst.elements():
        print i
    
    print '-' * 25
    print "reserved linked list:"

    lst.rev()
    for i in lst.elements():
        print i 

if __name__ == '__main__':
    main()

2 单链表的排序

在上面的 LList 类中加入两种排序算法:


class LList(object):
    #....
    def sort1(self):
        """
        方法1:搬动元素
        单独提取一个扫描指针,这个扫描指针从头部后面一个位置开始,
        扫描指针的值单独提出来,和扫描指针前的序列中的值依次对比,如果序列中的值大,序列的中的那个值就和指针的值进行交换,
        最后需要把扫描指针的值再赋给扫描指针的那个元素。
        如果前面序列中的值都比较过一遍以后,指针下移一位
        """
        if self._head is None:
            return
        # 从头部的下一个开始
        crt = self._head.next
        # 大循环
        while crt is not None:
            # 比较序列的操作,
            # 首先拿到序列指针p,且指向表头
            p = self._head
            # 另外,把扫描指针的值elem提取出来
            x = crt.elem
            # 如果序列中元素的值比扫描指针的值小,序列指针p向后移动一位,直到序列指针与 crt 扫描指针碰头
            while p is not crt and p.elem <= x:
                p = p.next
            while p is not crt:
                x, p.elem = p.elem, x
                p = p.next
            crt.elem = x
            crt = crt.next


    def sort(self):
        """
        方法2:操作链接
        从首结点的下一个开始进行大循环,一个扫描指针的基准点 last,用于扫描指针回归定位,以及扫描指针 crt
        小循环就看crt指向的结点是否需要插入,
        一旦需要插入,就把插入点前后的链接断开,都链接到新插入的 crt 指针的结点上。
        """
        if self._head is None:
            return
        last = self._head
        crt = last.next
        while crt is not None:
            p = self._head
            q = None
            while p is not crt and p.elem <= crt.elem:
                q = p
                p = p.next
            if p is crt:
                last = crt
            else:
                last = crt.next
                crt.next = p
                # 检查q是否为节点,如果不是节点就把首结点设为crt,如果是节点就把q的next连接到crt
                if q = None:
                    self._head = crt
                else:
                    q.next = crt
            crt = last.next

    

参考:
python数据结构与算法之list(三)
关于勘误,以及对于本书的初体验

你可能感兴趣的:(Python 单向链接表反转与排序)