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

循环链表

循环链表就是最后一个结点的指针域指向头结点,整个链表形成一个环。

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第1张图片

创建一个结点类:

class Node(object):
    """创建一个结点类"""
    def __init__(self, data):
        self.data = data
        self.next = None

创建一个创建循环链表的类:

接下来的一些操作循环链表的函数,都将写在这个类中

class create_circular_linked_list(object):
    """创建一个创建循环链表的类"""
    def __init__(self):
        self.head = None

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

获取循环链表的长度:

大体流程:

  1. 先在while中判断当前结点是否为空,若当前结点不为空,则长度加一
  2. 然后再判断是否为尾结点,如果是不是尾结点,继续后移判断
def length(self):
    """获取循环链表的长度"""
    cur = self.head
    count = 0
    while cur is not None:
        count += 1
        # 如果当前结点的下一个结点是头结点,说明这个结点就是尾结点
        # 如果不是,就将指针向后移动一个
        if cur.next == self.head:
            break
        else:
            cur = cur.next
    return count

遍历链表,并打印出来:

为什么要考虑链表为空的情况?

答:如果直接就需要使用cur.next,这种情况就需要考虑链表为空的情况。

因为如果链表为空时,是没有.next属性的,.next属性是结点的属性,空链表没有结点,所以需要考虑链表为空的情况。

def travel(self):
    """遍历链表"""
    if self.is_empty():
        return
    cur = self.head
    print(cur.data)
    while cur.next != self.head:
        cur = cur.next
        print(cur.data)

在头部添加结点(头插法):

如果链表为空的情况:添加的结点就是头结点,头结点的后继结点还是头结点

 【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第2张图片

如果链表不为空的情况: 

  1. 将指针移动到尾部结点
  2. 尾部结点指向新节点
  3. 新结点指向原来的头结点
  4. 再将头结点的称号给新结点

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第3张图片

def add_first(self, data):
    """在头部添加结点"""
    node = Node(data)
    if self.is_empty():
        self.head = node
        node.next = self.head
    else:
        cur = self.head
        # 将指针移动到尾部结点
        while cur.next is not self.head:
            cur = cur.next
        # 尾部结点指向新节点
        cur.next = node
        # 新结点指向原来的头结点
        node.next = self.head
        # 再将头结点的称号给新结点
        self.head = node  

在尾部添加结点(尾插法):

如果链表为空的情况:添加的结点就是头结点,头结点的后继结点还是头结点

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第4张图片

如果链表不为空的情况:

  1. 先将指针移动到尾部
  2. 尾部结点指向新结点
  3. 新结点指向头结点

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第5张图片

(不知道你有没有发现,循环链表的头插法和尾插法很相似,只差最后一行代码,可以思考一下这是为什么)

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

在指定位置插入结点:

三种情况:

1、插入出错:索引位置不在链表长度范围之内

2、插入头部:直接调用头插法的函数

3、插入中间:

  1. 指针移动到插入位置
  2. 将插入位置的前一个结点(pre)指向新结点
  3. 新结点指向原来的当前结点(cur)

(当链表为空时,我们只能插入到第0个位置,也就是调用头插法即可,当链表不为空时,即可正常插入)

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第6张图片

def insert_node(self, index, data):
    """在指定位置插入结点"""
    node = Node(data)
    if index < 0 or index > self.length():
        print("插入位置错误")
        return False
    elif index == 0:
        self.add_first(data)
    elif index == 0:
        self.add_last()
    else:
        cur = self.head
        pre = None # pre为当前指针所指向结点的前一个结点
        count = 0
        # 将指针移动到要插入的位置
        while count < index:
            pre = cur
            cur = cur.next
            count += 1
        pre.next = node
        node.next = cur

删除指定结点:

1、链表为空的情况:没有结点可删除,直接返回

2、链表不为空的情况:

1、要删除的结点就是头结点:

        1、指针移到尾部

        2、尾结点指向头结点的下一个(跳过头结点)

        3、将头结点的称号给头结点的下一个(让原头结点的下一个,成为新的头结点)

2、要删除的结点不是头结点

        1、移动到要删除结点的位置

        2、将要删除结点(cur)的前驱节点(pre)指向要删除结点(cur)的后继结点(如下图所示,也就是跳过了中间要删除的结点,以达到删除的目的)

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第7张图片

def remove_node(self, data):
    """删除指定结点"""
    if self.is_empty():
        return
    # 如果要删除的结点就是头结点
    elif data == self.head.data:
        # 如果链表只有一个头结点
        if self.head.next is self.head:
            self.head = None
        else:
            cur = self.head
            while cur.next != self.head:
                cur = cur.next
            cur.next = self.head.next
            self.head = self.head.next
    else:
        cur = self.head
        pre = None
        # 移动到要删除结点的位置
        while cur.data != data:
            # 如果没找到
            if cur.next == self.head:
                return
            pre = cur
            cur = cur.next
        # 将要删除的结点的前驱结点指向后继结点,这样就跳过了中间的结点
        pre.next = cur.next

 

查找指定结点是否存在:

(因为我们在while中直接判断当前结点是否为空,所以不需要再单独考虑链表是否为空的情况了)

然后我们需要考虑三种情况:

  1. 找到所查结点:直接返回True,查找成功
  2. 已经查到尾部了(因为是循环链表,尾部的下一个又是头结点,会无限循环下去,所以如果查到尾结点还没有找到,那就可以直接返回False了)
  3. 没找到的情况:那就令指针后移,继续找下个结点
def is_exist(self, data):
    """查找指定结点是否存在"""
    cur = self.head
    while cur is not None:
        # 找到所查结点
        if cur.data == data:
            return True
        # 已经查到尾部了
        elif cur.next == self.head:
            return False
        else:
            cur = cur.next
    return False

主函数测试:

if __name__ == '__main__':
    lists = create_circular_linked_list()
    lists.add_last(2)
    lists.add_first(1)
    lists.add_first(0)
    lists.add_last(3)
    lists.insert_node(2, 8)
    lists.travel()
    print("链表长度:", lists.length())
    lists.remove_node(8)
    lists.travel()
    print(lists.is_exist(2))

 测试结果截图:

【数据结构】——循环链表,使用Python创建一个简单的循环链表(详解)_第8张图片

完整代码

class Node(object):
    """创建一个结点类"""
    def __init__(self, data):
        self.data = data
        self.next = None

class create_circular_linked_list(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
            # 如果当前结点的下一个结点是头结点,说明这个结点就是尾结点
            # 如果不是,就将指针向后移动一个
            if cur.next == self.head:
                break
            else:
                cur = cur.next
        return count

    def add_first(self, data):
        """在头部添加结点"""
        node = Node(data)
        if self.is_empty():
            self.head = node
            node.next = self.head
        else:
            cur = self.head
            # 将指针移动到尾部结点
            while cur.next is not self.head:
                cur = cur.next
            # 尾部结点指向新节点
            cur.next = node
            # 新结点指向原来的头结点
            node.next = self.head
            # 再将头结点的称号给新结点
            self.head = node

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

    def insert_node(self, index, data):
        """在指定位置插入结点"""
        node = Node(data)
        if index < 0 or index > self.length():
            print("插入位置错误")
            return False
        elif index == 0:
            self.add_first(data)
        else:
            cur = self.head
            pre = None # pre为当前指针所指向结点的前一个结点
            count = 0
            # 将指针移动到要插入的位置
            while count < index:
                pre = cur
                cur = cur.next
                count += 1
            pre.next = node
            node.next = cur

    def remove_node(self, data):
        """删除指定结点"""
        if self.is_empty():
            return
        # 如果要删除的结点就是头结点
        elif data == self.head.data:
            # 如果链表只有一个头结点
            if self.head.next is self.head:
                self.head = None
            else:
                cur = self.head
                while cur.next != self.head:
                    cur = cur.next
                cur.next = self.head.next
                self.head = self.head.next
        else:
            cur = self.head
            pre = None
            # 移动到要删除结点的位置
            while cur.data != data:
                # 如果没找到
                if cur.next == self.head:
                    return
                pre = cur
                cur = cur.next
            # 将要删除的结点的前驱结点指向后继结点,这样就跳过了中间的结点
            pre.next = cur.next

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            return
        cur = self.head
        print(cur.data)
        while cur.next != self.head:
            cur = cur.next
            print(cur.data)

    def is_exist(self, data):
        """查找指定结点是否存在"""
        cur = self.head
        while cur is not None:
            # 找到所查结点
            if cur.data == data:
                return True
            # 已经查到尾部了
            elif cur.next == self.head:
                return False
            else:
                cur = cur.next
        return False


if __name__ == '__main__':
    lists = create_circular_linked_list()
    lists.add_last(2)
    lists.remove_node(2)
    print(lists.is_empty())
    lists.add_first(1)
    lists.add_first(0)
    lists.add_last(3)
    lists.insert_node(2, 8)
    lists.travel()
    print("链表长度:", lists.length())
    lists.remove_node(8)
    lists.travel()
    print(lists.is_exist(2))

因为循环链表是一个闭合的环,所以我们遍历的时候,从链表的任意一个位置开始遍历都可以,而要注意的是设定好遍历结束的条件。  

你可能感兴趣的:(数据结构)