【数据结构】——双向链表,使用Python创建一个简单的双向链表(详解)

双向链表

双向链表有两个指针域,一个指向前驱结点,一个指向后继结点

创建一个结点类:

因为是双向链表,所以需要前后相通,就是比单链表多了一个前驱指针

数据域data、前驱指针pre,后继指针next

class Node(object):
    """创建一个结点类"""

    def __init__(self, data):
        self.data = data
        self.pre = None
        self.next = None

创建一个创建双向链表的类:

判断是否为空、获取长度、遍历链表、查找指定结点是否存在,这些函数和单链表的一样

(只是最简单的方法一样,双向链表还有其它方法遍历或者查找指定结点)

class CreateDoubleLinkedList(object):
    """创建一个创建双向链表的类"""

    def __init__(self):
        self.head = None

    def is_empty(self):
        """判断双向链表是否为空链表"""
        return self.head is None

    def length(self):
        """获取双向链表的长度"""
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def traversal(self):
        """遍历双向链表"""
        cur = self.head
        if self.is_empty():
            print("链表为空!")
            return
        while cur is not None:
            print(cur.data)
            cur = cur.next
        
    def node_is_exist(self, data):
        """查找指定结点是否存在"""
        cur = self.head
        while cur is not None:
            if cur.data == data:
                return True
            else:
                cur = cur.next
        return False   

在头部添加结点:

插入的大体过程和单链表很相似,只是在插入结点的过程中,我们需要注意的就是:每个结点都有两个指针,都需要设置正确的指向。

def add_first(self, data):
    """在头部添加结点"""
    node = Node(data)
    if self.is_empty():
        self.head = node
    else:
        # 新结点向后指向头结点
        node.next = self.head
        # 头结点向前指向新结点
        self.head.pre = node
        # 将头结点的称号给新结点
        self.head = node

在尾部添加结点:

def add_last(self, data):
    """在尾部添加结点"""
    node = Node(data)
    if self.is_empty():
        self.head = node
    else:
        cur = self.head
        # 指针移动到尾部
        while cur.next is not None:
            cur = cur.next
        # 尾结点的后继指针指向新结点
        cur.next = node
        # 新结点的前驱指针指向尾结点
        node.pre = cur

在指定位置添加结点:

def insert_node(self, index, data):
    """在指定位置添加结点"""
    if index < 0 or index > self.length():
        print("结点位置错误!")
        return False
    elif index == 0:
        self.add_first(data)
    elif index == self.length():
        self.add_last(data)
    else:
        node = Node(data)
        cur = self.head
        pres = None
        count = 0
        # 移动到要添加的位置
        while count < index:
            pres = cur
            cur = cur.next
            count += 1
        # 新结点和它前面的结点互指
        pres.next = node
        node.pre = pres
        # 新结点和它后面的结点互指
        node.next = cur
        cur.pre = node

删除指定结点:

当链表不为空的时候,我们需要考虑三种情况:

  1. 要删除是是头结点
  2. 要删除的是尾结点
  3. 要删除的是中间任意结点

(需要注意的就是:每个结点都需要改变两个指针链)

def remove_node(self, data):
    """删除指定结点"""
    if self.is_empty():
        print("删除失败,链表为空!")
        return False
    elif data == self.head.data:
        self.head.next.pre = None
        self.head = self.head.next
    else:
        cur = self.head
        # 移动到要删除结点的位置
        while cur.data != data:
            cur = cur.next
        # 当前结点的后继结点为空,说明是尾结点
        if cur.next is None:
            cur.pre.next = None
            cur.pre = None
        else:
            cur.pre.next = cur.next
            cur.next.pre = cur.pre

假如我们只断掉了一根指针链,会怎么样?

就比如这样写(以上面删除尾结点的代码为例):

# 当前结点的后继结点为空,说明是尾结点
        if cur.next is None:
            cur.pre.next = None
            # 将尾结点指向前驱结点的那个指针链留着
            # cur.pre = None
            # 打印一下被删掉的尾结点的前驱结点数据 
            print("测试:", cur.pre.data)

如果尾结点已经被删掉了,那么cur指向为空,最后print那一行,空类型是没有前驱结点pre属性的,测试运行之后,肯定会报错。

但是因为我们只删掉了一个指针链,所以测试结果还是会打印出:被删除掉结点的前驱结点数据,因为被删除结点的前驱指针链没有被断掉。

接下来我们正向遍历一次链表,发现:没有被刚才删除的结点数据,为什么?因为向右的指针链已经被断掉了,遍历不到它,我们以为被它被删除掉了,其实没有。

所以:双向链表必须要端两根指针链,才能彻底删除掉。

(可以自行写一个反向遍历的函数,看一看效果)

主函数测试:

if __name__ == '__main__':
    lists = CreateDoubleLinkedList()
    lists.add_last(3)
    lists.add_first(2)
    lists.add_first(1)
    lists.add_last(5)
    lists.insert_node(3, 4)
    lists.traversal()
    print("链表是否为空:", lists.is_empty())
    print("获取链表长度:", lists.length())
    print("改结点是否存在:", lists.node_is_exist(2))
    lists.remove_node(1)
    lists.remove_node(5)
    print("删除结点之后的遍历:")
    lists.traversal()

测试结果截图:

完整代码:

class Node(object):
    """创建一个结点类"""

    def __init__(self, data):
        self.data = data
        self.pre = None
        self.next = None


class CreateDoubleLinkedList(object):
    """创建一个创建双向链表的类"""

    def __init__(self):
        self.head = None

    def is_empty(self):
        """判断双向链表是否为空链表"""
        return self.head is None

    def length(self):
        """获取双向链表的长度"""
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def traversal(self):
        """遍历双向链表"""
        cur = self.head
        if self.is_empty():
            print("链表为空!")
            return
        while cur is not None:
            print(cur.data)
            cur = cur.next

    def node_is_exist(self, data):
        """查找指定结点是否存在"""
        cur = self.head
        while cur is not None:
            if cur.data == data:
                return True
            else:
                cur = cur.next
        return False

    def add_first(self, data):
        """在头部添加结点"""
        node = Node(data)
        if self.is_empty():
            self.head = node
        else:
            # 新结点向后指向头结点
            node.next = self.head
            # 头结点向前指向新结点
            self.head.pre = node
            # 将头结点的称号给新结点
            self.head = node

    def add_last(self, data):
        """在尾部添加结点"""
        node = Node(data)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            # 指针移动到尾部
            while cur.next is not None:
                cur = cur.next
            # 尾结点的后继指针指向新结点
            cur.next = node
            # 新结点的前驱指针指向尾结点
            node.pre = cur

    def insert_node(self, index, data):
        """在指定位置添加结点"""
        if index < 0 or index > self.length():
            print("结点位置错误!")
            return False
        elif index == 0:
            self.add_first(data)
        elif index == self.length():
            self.add_last(data)
        else:
            node = Node(data)
            cur = self.head
            pres = None
            count = 0
            # 移动到要添加的位置
            while count < index:
                pres = cur
                cur = cur.next
                count += 1
            # 新结点和它前面的结点互指
            pres.next = node
            node.pre = pres
            # 新结点和它后面的结点互指
            node.next = cur
            cur.pre = node

    def remove_node(self, data):
        """删除指定结点"""
        if self.is_empty():
            print("删除失败,链表为空!")
            return False
        elif data == self.head.data:
            self.head.next.pre = None
            self.head = self.head.next
        else:
            cur = self.head
            # 移动到要删除结点的位置
            while cur.data != data:
                cur = cur.next
            # 当前结点的后继结点为空,说明是尾结点
            if cur.next is None:
                cur.pre.next = None
                cur.pre = None
            else:
                cur.pre.next = cur.next
                cur.next.pre = cur.pre


if __name__ == '__main__':
    lists = CreateDoubleLinkedList()
    lists.add_last(3)
    lists.add_first(2)
    lists.add_first(1)
    lists.add_last(5)
    lists.insert_node(3, 4)
    lists.traversal()
    print("链表是否为空:", lists.is_empty())
    print("获取链表长度:", lists.length())
    print("改结点是否存在:", lists.node_is_exist(2))
    lists.remove_node(1)
    lists.remove_node(5)
    print("删除结点之后的遍历:")
    lists.traversal()
发布了22 篇原创文章 · 获赞 17 · 访问量 5852

猜你喜欢

转载自blog.csdn.net/weixin_42193813/article/details/104282496