美文网首页
链表(三)

链表(三)

作者: 小董不太懂 | 来源:发表于2019-10-11 16:50 被阅读0次

    单向链表

    class Node():
        '''节点'''
        def __init__(self,elem):
            self.elem = elem
            self.next = None
    
    class SingleLinkList(object):
        '''单链表'''
        def __init__(self,node=None):
            #内部私有函数,链表头的初始化,可以直接建立空链表
            self.__head = node
    
        def is_empty(self):
            """判断链表是否为空"""
            return self.__head == None
    
        def length(self):
            """返回链表的长度"""
            #cur游标,用来移动遍历节点
            #count,用来记录节点数量
            count = 0
            cur = self.__head
            while cur != None:
                count += 1
                cur = cur.next
            return count
    
        def travel(self):
            """遍历链表"""
            cur = self.__head
            while cur != None:
                print(cur.elem,end=' ')
                cur = cur.next
    
        def add(self, item):
            """头部添加节点"""
            node = Node(item)
            node.next = self.__head
            self.__head = node
    
        def append(self, item):
            """尾部添加节点"""
            node = Node(item)
            if self.is_empty():
                self.__head = node
            else:
                cur = self.__head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
    
        def insert(self, pos, item):
            """在指定位置添加节点"""
            pre = self.__head
            count = 0
            if pos <= 0:
                self.add(item)
            elif pos >= (self.length()-1):
                self.append(item)
            else:
                while count < (pos-1):
                    count += 1
                    pre = pre.next
                node = Node(item)
                node.next = pre.next
                pre.next = node
    
        def remove(self, item):
            """删除一个节点"""
            cur = self.__head
            pre = None
            while cur != None:
                if cur.elem == item:
                    #先判断是否为头节点,然后再去处理头节点
                    if cur == self.__head:
                        self.__head = cur.next
                    else:
                        pre.next = cur.next
                    break
                else:
                    pre = cur
                    cur = cur.next
    
    
        def search(self, item):
            """查找节点是否存在"""
            cur = self.__head
            while cur != None:
                if cur.elem == item:
                    return True
                else:
                    cur = cur.next
            return False
    
    根据这段代码,结合下图,是不是进一步加深了我们对时间复杂度的理解。
    • 链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。
    • 注意虽然表面看起来复杂度都是 O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。

    双向链表

    100节点是40节点的前驱节点,6节点是40节点的后继节点。
    一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
    代码实现,我们就在单向链表的基础上更改
    • 我们先看看双链表的构造

      是不是和单链表如出一辙,无需更改程序。

    • 我们看看双链表的探空功能:

      这样是不是又和单链表一样了。

    • 我们看看求长度的功能: 我们只需要计数,是不是完全可以把它当成单链表,只需要一个游标next就可以实现求长度啊,遍历的travel和求长度一样都可以看作是单链表,简单粗暴。
    • 我们看看从头部添加的功能: 我们是不是要先操作新节点啊 这样就可以实现。
      但如果用代码实现的话,可以有两种方式,与指向的前后顺序相关:

      1 方法一

     def add(self, item):
            """头部添加节点"""
            node = Node(item)
            node.next = self.__head
            self.__head = node
            node.next.prev = node
    

    2 方法二

        def add(self, item):
            """头部添加节点"""
            node = Node(item)
            node.next = self.__head
            self.__head.prev = node
            self.__head = node
    
    • 实现链表尾部添加元素的功能:

      尾插法是不是首先要定位啊,定位到最后一个元素,这个过程双链表和单链表是没有区别的,定位到最后一个元素后 只要实现这样的指向就OK了吧,那要怎么实现呢。
        def append(self, item):
            """尾部添加节点"""
            node = Node(item)
            if self.is_empty():
                self.__head = node
            else:
                cur = self.__head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
                node.prev = cur
    

    考虑一下特殊情况,加入这个链表为空链表呢,程序也是没问题的。

    • 实现insert插入功能:

      我们先截个单链表中的insert代码 我们看看双链表中需要怎么更改呢? 这一部分是不需要更改的吧,位置小于等于0我们就调用头插法,pos大于等于(length() - 1,我们就调用尾插法。唯一需要更改的就是,最后的指向问题。 这么一来是不是就一目了然
    • 先操作node节点,让node节点分别指向节点6和节点40,node.next = cur,node.prev = cur.prev
    • 然后让节点40和节点6分别对接node节点,cur.prev.next = node,cur.prev = node


      这么写也可以。
      那么完整的代码怎么实现呢,显然需要做一些更改,首先pre这个游标就不需要了,我们只需要一个cur游标,且count < pos即可。

        def insert(self, pos, item):
            """在指定位置添加节点"""
            cur = self.__head
            count = 0
            if pos <= 0:
                self.add(item)
            elif pos >= (self.length() - 1):
                self.append(item)
            else:
                while count < pos:
                    count += 1
                    cur = cur.next
                node = Node(item)
                node.next = cur
                node.prev = cur.prev
                cur.prev.next = node
                cur.prev = node
    
    测试结果没问题
    • 实现删除的功能: 那如果要删除的是头节点要怎么处理呢? 这样是不是OK
      那如果原有的链表只有一个节点要如何处理呢?我们还是直接看代码吧。
     def remove(self, item):
            """删除一个节点"""
            cur = self.__head
            while cur != None:
                if cur.elem == item:
                    # 先判断是否为头节点,然后再去处理头节点
                    if cur == self.__head:
                        self.__head = cur.next
                        if cur.next:
                            cur.next.prev = None
                    else:
                        cur.prev.next = cur.next
                        if cur.next:
                           cur.next.prev = cur.prev
                    break
                else:
                    cur = cur.next
    
    测试结果一切正常

    相关文章

      网友评论

          本文标题:链表(三)

          本文链接:https://www.haomeiwen.com/subject/ppmapctx.html