数据结构(二)双向链表的的分析与python代码实现

版权声明:尊重原作者,转载请在文章头部注明网址。 https://blog.csdn.net/u013034226/article/details/85792888

概念

       每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。

特点:
        节点包含三个域,一个元素域,两个链接域(前驱和后继),第0个节点没有前驱,最后一个节点没有后继,在单链表的基础上,增加向前指向的考虑。

结构

python代码实现 

class Node(object):
    """实现双向链表节点"""
    def __init__(self, item):
        # item存放数据元素
        self.item = item
        # next代表后一个节点
        self.next = None
        # prev代表前一个节点
        self.prev = None


class DoubleLinkList(object):
    """双向链表"""
    def __init__(self):
        # 表示首节点
        self.head = None

    # 链表是否为空
    def is_empty(self):
        return self.head is None

    # 链表长度
    def length(self):

        # cur初始时指向头节点
        cur = self.head
        n = 0
        # 当未到达尾节点None时
        while cur is not None:
            n += 1
            # 将cur后移一个节点
            cur =cur.next

        return n

    # 遍历整个链表
    def travel(self):
        cur = self.head
        while cur is not None:
            print(cur.item, end='-')
            cur = cur.next
        # 输出链表
        print()


    # 链表头部添加元素
    def add(self, item):
        # 调用Node类,实例node对象
        node = Node(item)

        # 先让新增加的节点next指向原首节点
        node.next = self.head
        # 然后让head指向新节点
        self.head = node
        # 原首节点存在时,原首节点向前指向新节点,实现双向
        if node.next is not None:
            node.next.prev = node



    # 链表尾部添加元素
    def append(self, item):

        # 若链表为空,则直接在头部添加
        if self.is_empty():
            self.add(item)
            return
        # 1、链表不为空,需要遍历查找尾节点
        cur = self.head
        while cur.next is not None:
            cur = cur.next

        # 至此cur指向当前链表的尾节点
        # 2、让cur的next指向新节点
        node = Node(item)
        cur.next = node
        # 3、新节点向前指向cur
        node.prev = cur

    # 指定位置添加元素
    def insert(self, pos, item):
        # 需要对添加的位置进行分类讨论
        # 如果添加位置<=0,则直接在头部添加
        if pos <= 0:
            self.add(item)
        # 位置大于链表长度,则直接添加到尾部
        elif pos >= self.length():
            self.append(item)
        else:
            # 1 遍历查找待插入位置的前一个节点cur
            cur = self.head
            for i in range(pos-1):
                cur = cur.next
            # 至此,cur指向的就是待插入位置的前一个节点
            # 2 新节点的next指向cur的next
            node = Node(item)
            node.next = cur.next
            # 3 cur的next指向新节点
            cur.next = node
            # 4 新节点的后继节点向前指向新节点(双向,向前)
            node.next.prev = node
            # 5 新节点向前指向cur(双向,向前)
            node.prev = cur

    # 删除节点
    def remove(self, item):
        # 思路:让待删节点的pre(前节点)next指向待删节点的next
        cur = self.head
        # 1 找到待删节点并记录前一个节点
        while cur is not None:
            # 待删节点不存在也就不用删了,若存在
            if cur.item == item:
                # 2 若cur有前驱节点则:cur的前驱节点指向cur的后继节点,越过待删节点
                if cur.prev is not None:
                    cur.prev.next = cur.next
                # 否则(待删节点是第0个节点),head指向待删节点的next
                else:
                    self.head = cur.next
                # 3 若cur有后继节点,则cur的后继节点向前指向cur的前驱节点(越过待删节点)
                if cur.next is not None:
                    cur.next.prev = cur.prev

                return
            cur = cur.next


    # 查找某个节点是否存在
    def search(self, item):
        cur = self.head
        while cur is not None:
            if cur.item == item:
                return True
            cur = cur.next

        # 没有找到
        return False


# 测试代码
if __name__ == '__main__':
    dl = DoubleLinkList()
    dl.add(1)
    dl.add(2)
    dl.add(3)
    dl.travel()
    # 结果3-2-1-
    dl.append("abc")
    dl.append("def")
    dl.append("ghi")
    dl.travel()
    # 结果3-2-1-abc-def-ghi-
    dl.insert(-1, "xx")
    dl.insert(99, "yy")
    dl.insert(3, "zz")
    dl.travel()
    # 结果xx-3-2-zz-1-abc-def-ghi-yy-
    dl.remove("xx")
    dl.remove("yy")
    dl.remove(1)
    dl.remove(90)
    dl.travel()
    # 结果3-2-zz-abc-def-ghi-
    print(dl.search(3))
    # 结果True
    print(dl.search("zz"))
    # 结果True
    print(dl.search(380))
    # 结果False

复杂度

头部添加O(1),尾部添加O(n),指定位置添加O(n),

删除节点:

若cur有前驱节点则:cur的前驱节点指向cur的后继节点 O(n),否则:head指向cur的后继节点 O(1)

猜你喜欢

转载自blog.csdn.net/u013034226/article/details/85792888