单向循环链表

316 阅读3分钟
#!/usr/bin/env python3
# -*- encoding:utf-8 -*-
"""
@author: jjcoder
@file: SingleCycleLinkList.py
@time: 9/11/197:31 AM
"""


class Node(object):
    def __init__(self, item):
        self.elem = item
        self.next = None


class SingleCycleLinkList(object):
    """单向循环链表"""

    def __init__(self, node=None):
        self.__head = node
        if node:  # 这里要注意,如果初始化链表时.节点不为空,那么需要让节点的next区域指向自己
            node.next = node

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

    # 链表的长度
    def length(self):
        if self.is_empty():  # 如果链表为空,那么下面的循环判断将不适用,直接return 0;
            return 0
        cur = self.__head
        count = 1  # 注意这里为什么选择1
        while cur.next != self.__head:  # 这里是循环的终止条件(只有一个节点的情况也是满足的)
            count += 1
            cur = cur.next
        return count

    # 遍历链表
    def travel(self):
        if self.is_empty():  # 当链表为空时直接返回
            return
        cur = self.__head  # 对于单个节点的时候也是满足条件的
        while cur.next != self.__head:
            print(cur.elem, end=" ")
            cur = cur.next
        # 退出循环,cur指向尾节点,但是却未打印尾节点,这是需要打印一下尾节点
        print(cur.elem, end=" ")
        print()

    # 在头部插入元素
    def add(self, item):
        node = Node(item)
        if self.is_empty():  # 空链表的处理方式
            self.__head = node
            node.next = node
        else:
            # 先不在链表中插入节点,然后对链表遍历找到尾节点,然后记录下来(用于后面头插法使用)
            # 另外一种方式是: 先在链表中插入一个节点,然后遍历新的链表
            cur = self.__head
            while cur.next != self.__head:  # 单个节点这里也满足
                cur = cur.next
            # 退出循环,cur指向尾节点
            node.next = self.__head
            self.__head = node
            cur.next = node  # 这后面的写法比较灵活,自行选择

    # 在尾部插入元素
    def append(self, item):
        node = Node(item)
        if self.is_empty():  # 当链表为空时
            self.__head = node
            node.next = node
        else:
            cur = self.__head  # 对于只有一个节点的情况也满足
            while cur.next != self.__head:
                cur = cur.next
            node.next = self.__head
            cur.next = node

    # 在任意位置插入元素
    def insert(self, pos, item):
        # 这里的pos是从0开始的
        node = Node(item)
        # 如果pos<=0理解为在头部插入元素,不支持反向插入
        if pos <= 0:
            self.add(item)
        # 如果pos>length() - 1, 就理解为在尾部插入元素,但是这里需要注意如果pos=length - 1,并不是在尾部插入元素,
        # 而是在最后面元素的前一位插入.
        elif pos > (self.length() - 1):
            self.append(item)
        else:
            cur = self.__head
            # for i in range(pos - 1):  # 这种方式也是可以的
            count = 0
            while count < (pos - 1):
                # 为防止后面的节点被丢弃,先将新节点的next区域指向cur的next区域,然后在将cur的next指向新节点
                # 这里也可以定义一个pre游标,为了方便继续使用cur游标
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    # 查找元素
    def search(self, item):
        if self.is_empty():  # 判断链表为空时
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        # 这里会出现最后一个节点没有被判断(cur指向尾节点), 所以这里需要特殊判断
        if cur.elem == item:
            return True
        return False

    # 删除元素
    def remove(self, item):
        if self.is_empty():  # 判断链表为空
            return
        cur = self.__head
        pre = None
        # 如果是空链表也是满足条件的
        while cur.next != self.__head:
            if cur.elem == item:
                # 如果删除的元素恰好是首节点
                # 如果链表只有一个节点,下面的操作也满足
                # 先判断此节点是否是头节点
                if cur == self.__head:
                    # 头节点插入元素
                    # 找到为节点
                    rear = self.__head
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:
                    # 如果删除的节点是尾节点,下面也是可以不满足条件的(因为尾节点并没有进入循环)
                    # 中间节点插入元素
                    pre.next = cur.next
                return  # 这里把break改成return就可以了
            else:
                # 下面这两行代码顺序不能变
                pre = cur
                cur = cur.next
        # 退出循环,cur指向尾节点
        if cur.elem == item:
            if cur == self.__head:  # 链表只有一个节点
                self.__head = None
            else:
                pre.next = cur.next  # 这里出现过问题,需要着重注意


if __name__ == "__main__":
    single_obj = SingleCycleLinkList()