您的位置:首页 > 理论基础 > 数据结构算法

Python全栈(二)数据结构和算法之4.单向循环链表的实现

2020-01-11 13:26 417 查看

文章目录

  • 二、单项循环链表遍历、头插法&尾插法
  • 三、单项循环链表删除&搜索
  • 一、单项循环链表长度&判空实现

    1.循环链表定义

    是一种特殊的单链表,唯一的区别是:
    单链表的尾结点指针指向空地址,表示这就是最后的结点了;
    循环链表的尾结点指针是指向链表的头结点。

    2.is_empty()

    与单链表一致。

    def is_empty(self):
    '''判断是否为空'''
    return self.__head == None

    3.length()

    cur.next = self.__head
    时循环结束,且因最后一次循环不会执行,所以count不会加1,所以count要哦才能够1开始计数。
    并且为空时,直接返回0。

    def length(self):
    '''链表长度'''
    #判断是否为空链表
    if self.is_empty():
    return 0
    # cur即游标,指向首节点,用来遍历
    cur = self.__head
    count = 1
    # 当未到达尾部时
    while cur.next != self.__head:
    count += 1
    # 将游标向后移动一位
    cur = cur.next
    return count

    二、单项循环链表遍历、头插法&尾插法

    1.遍历travel()

    cur.next = self.__head
    时循环结束。
    空链表时直接返回。

    def travel(self):
    '''遍历链表'''
    #链表为空时
    if self.is_empty():
    return
    cur = self.__head
    while cur.next != self.__head:
    print(cur.item, end=' ')
    cur = cur.next
    #退出循环时,cur指向尾节点,单独打印
    print(cur.item)

    2.头部添加add():

    将新节点指向head的下一个节点,head指向新节点,尾节点指向新节点,第三步顺序可以在第一或第二步。
    为空链表时,__head指向新节点,新节点指向自己(即__head)。

    def add(self, item):
    '''链表尾部添加元素'''
    # 创建一个保存数据的节点
    node = Node(item)
    # 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
    if self.is_empty():
    self.__head = node
    node.next = self.__head #等价于node.next = node
    #若不为空
    else:
    cur = self.__head
    #找到尾部
    while cur.next != self.__head:
    cur = cur.next
    #新节点指向__head
    node.next = self.__head
    #__head指向新节点
    self.__head = node
    # 将尾节点指向新节点,此句可以在self.__head = node或node.next = self.__head之前
    cur.next = node

    3.append()尾部添加

    找到尾节点:
    尾节点指向新节点,新节点指向头部。
    也要判断是否为空链表。

    def append(self, item):
    '''链表尾部添加元素'''
    # 创建一个保存数据的节点
    node = Node(item)
    #判断是否为空链表
    if self.is_empty():
    self.__head = node
    node.next = self.__head  # 等价于node.next = node
    else:
    cur = self.__head
    # 找到尾节点
    while cur.next != self.__head:
    cur = cur.next
    # 尾节点指向新节点
    cur.next = node
    #新节点指向__head
    node.next = self.__head

    三、单项循环链表删除&搜索

    1.insert()

    新节点指向目标位置,目标位置前一个位置指向新节点。

    def insert(self, pos, item):
    '''指定位置添加元素'''
    # 若指定位置为第一个位置之前,则执行头部插入
    if pos <= 0:
    self.add(item)
    # 若指定位置超过链表尾部,则执行尾部插入
    elif pos > self.length() - 1:
    self.append(item)
    # 找到指定位置
    else:
    node = Node(item)
    cur = self.__head
    count = 0
    while count < pos - 1:
    count += 1
    cur = cur.next
    # 将新节点node的next指向插入位置的节点
    node.next = cur.next
    # 将插入位置的前一个节点的next指向新节点
    cur.next = node

    2.search()

    如果为空,直接返回False。
    并且在循环后判断尾节点是否符合。

    def search(self, item):
    '''查找节点是否存在'''
    if self.is_empty():
    return False
    cur = self.__head
    while cur.next != self.__head:
    # 判断第一个节点
    if cur.item == item:
    return True
    # 未找到,继续向后移动
    else:
    cur = cur.next
    #循环退出,cur指向尾节点
    if cur.item == item:
    return True
    return False

    3.remove()

    如果删除的节点为头节点:
    如果不止头节点一个节点,__head指向当前的下一个节点;
    如果只有head一个节点,则__head指向None。
    如果删除的节点不是头节点:

    pre.next = cur.next
    ,并且需要循环,同时要对尾节点进行判断。

    def remove(self, item):
    '''删除节点'''
    #如果链表为空,直接返回
    if self.is_empty():
    return
    cur = self.__head
    pre = None
    #头节点的元素就是要删除的元素
    if cur.item == item:
    #链表中的节点不止一个
    if cur.next != self.__head:
    while cur.next != self.__head:
    cur = cur.next
    #循环结束,cur指向尾节点
    cur.next = self.__head.next
    self.__head = cur.next
    #只有一个节点
    else:
    self.__head = None
    #头节点不是要删除的元素
    else:
    while cur.next != self.__head:
    if cur.item == item:
    #删除
    pre.next = cur.next
    return
    #继续往后遍历
    else:
    pre = cur
    cur = cur.next
    #要删除的节点是最后一个元素时
    if cur.item == item:
    pre.next = cur.next #pre.next = self.__head也可

    整个单项循环链表的实现如下:

    class Node(object):
    '''节点'''
    def __init__(self,item):
    '''初始化'''
    self.item = item
    #next是下一个节点的标识
    self.next = None
    
    class SinCycLinkList(object):
    '''循环链表'''
    def __init__(self,node = None):
    self.__head = None
    if node:
    node.next = node
    
    def is_empty(self):
    '''判断是否为空'''
    return self.__head == None
    def length(self):
    '''链表长度'''
    #判断是否为空链表
    if self.is_empty():
    return 0
    # cur即游标,指向首节点,用来遍历
    cur = self.__head
    count = 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.item, end=' ')
    cur = cur.next
    #退出循环时,cur指向尾节点,单独打印
    print(cur.item)
    def add(self, item):
    '''链表头部添加元素'''
    # 创建一个保存数据的节点
    node = Node(item)
    # 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
    if self.is_empty():
    self.__head = node
    node.next = self.__head #等价于node.next = node
    #若不为空
    else:
    cur = self.__head
    #找到尾部
    while cur.next != self.__head:
    cur = cur.next
    #新节点指向__head
    node.next = self.__head
    #__head指向新节点
    self.__head = node
    # 将尾节点指向新节点,此句可以在self.__head = node或node.next = self.__head之前
    cur.next = node
    
    def append(self, item):
    '''链表尾部添加元素'''
    # 创建一个保存数据的节点
    node = Node(item)
    #判断是否为空链表
    if self.is_empty():
    self.__head = node
    node.next = self.__head  # 等价于node.next = node
    else:
    cur = self.__head
    # 找到尾节点
    while cur.next != self.__head:
    cur = cur.next
    # 尾节点指向新节点
    cur.next = node
    #新节点指向__head
    node.next = self.__head
    def insert(self, pos, item):
    '''指定位置添加元素'''
    # 若指定位置为第一个位置之前,则指向头部插入
    if pos <= 0:
    self.add(item)
    # 若指定位置超过链表尾部,则执行尾部插入
    elif pos > self.length() - 1:
    self.append(item)
    # 找到指定位置
    else:
    node = Node(item)
    cur = self.__head
    count = 0
    while count < pos - 1:
    count += 1
    cur = cur.next
    # 将新节点node的next指向插入位置的节点
    node.next = cur.next
    # 将插入位置的前一个节点的next指向新节点
    cur.next = node
    
    def remove(self, item):
    '''删除节点'''
    #如果链表为空,直接返回
    if self.is_empty():
    return
    cur = self.__head
    pre = None
    #头节点的元素就是要删除的元素
    if cur.item == item:
    #链表中的节点不止一个
    if cur.next != self.__head:
    while cur.next != self.__head:
    cur = cur.next
    #循环结束,cur指向尾节点
    cur.next = self.__head.next
    self.__head = cur.next
    #只有一个节点
    else:
    self.__head = None
    #头节点不是要删除的元素
    else:
    while cur.next != self.__head:
    if cur.item == item:
    #删除
    pre.next = cur.next
    return
    #继续往后遍历
    else:
    pre = cur
    cur = cur.next
    #要删除的节点是最后一个元素时
    if cur.item == item:
    pre.next = cur.next #pre.next = self.__head也可
    def search(self, item):
    '''查找节点是否存在'''
    if self.is_empty():
    return False
    cur = self.__head
    while cur.next != self.__head:
    # 判断第一个节点
    if cur.item == item:
    return True
    # 未找到,继续向后移动
    else:
    cur = cur.next
    #循环退出,cur指向尾节点
    if cur.item == item:
    return True
    return False
    s = SinCycLinkList()
    print(s.is_empty())
    print(s.length())
    s.add(1)
    s.add(2)
    s.add(3)
    s.add(4)
    s.travel()
    s.append(5)
    s.append(6)
    s.insert(-1,7)
    s.insert(12,8)
    s.insert(5,9)
    s.travel()
    print(s.search(3))
    print(s.search(10))
    s.remove(6)
    s.travel()
    

    对单项循环链表进行测试,结果如下:

    True
    0
    4 3 2 1
    7 4 3 2 1 9 5 6 8
    True
    False
    7 4 3 2 1 9 5 8

    小结:

    单项循环链表的实现要结合单链表,要对它们的相同和不同之处进行比较。
    很显然,单向循环链表实现的时候要考虑的情况比单链表更多,也更复杂,要在对比中学习,举一反三。
    并且在每一个方法中

    cur.next != self.__head
    这个循环判断条件都出现了,所以找到实现的边界条件极为重要。
    同时,要考虑各种特殊情况,比如链表为空,只有一个节点,对尾节点的处理等情况。

    大家也可以关注我的公众号:Python极客社区,在我的公众号里,经常会分享很多Python的文章,而且也分享了很多工具、学习资源等。另外回复“电子书”还可以获取十本我精心收集的Python电子书。

    • 点赞 2
    • 收藏
    • 分享
    • 文章举报
    cupyter 发布了49 篇原创文章 · 获赞 179 · 访问量 2万+ 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: