链表(四)

荒废了一段时间,这段时间实验室事情多,就没怎么看数据结构(悲痛)。

什么是单向循环链表?

顾名思义,单向循环链表,就是在单向链表的基础上做一些改动,实现链表循环,即将原本尾节点的next指向None,现指向链表的头节点,这样一来就实现了所谓的单项循环链表。
单向循环链表

了解了大致的概念之后,我们需要用代码实现这个单向循环链表,单向循环链表的代码也是在单向链表的代码基础上进行更改。
节点的构造是没有区别的,可以直接用单向链表的代码。
那关于首节点,我们是不是需要一些改动啊,比如让它指向自己。

class Node():
    '''节点'''
    def __init__(self,elem):
        self.elem = elem
        self.next = None

class SingleLinkList(object):
    '''单向循环链表'''
    def __init__(self,node=None):
        #内部私有函数,链表头的初始化,可以直接建立空链表
        self.__head = node
        if node:
            node.next = node#self.__head指向node,如果node存在那还需要建立一个回环,让  note.next指向自己本身
  • 那么关于探空的功能呢?是不是也无需更改?答案是无需更改
    def is_empty(self):
        """判断链表是否为空"""
        return self.__head == None
  • 实现求长度的功能:

    单向链表结束的条件:cur == None或者cur == self.__head
    能否用在我们的单项循环链表呢,答案是不可以,因为单向链表的判断语句不仅在尾结点上复合,且在头节点也符合,故不可用。
    单向循环链表的结束条件:cur.next == seif.__head
    但是我们的count初始值为1,如果按照这个初值走,最后会少算一个节点,故初始值改为1。

    def length(self):
        """返回链表的长度"""
        #cur游标,用来移动遍历节点
        #count,用来记录节点数量
        count = 1
        cur = self.__head
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count

考虑一下,若链表为空链表怎么处理呢,若链表只有一个节点呢?

  def length(self):
        """返回链表的长度"""
        #cur游标,用来移动遍历节点
        #count,用来记录节点数量
        count = 1
        if self.is_empty():
            return 0
        cur = self.__head
        while cur.next != self.__head:#满足仅有一个节点的选项
            count += 1
            cur = cur.next
        return count
  • 如何实现遍历功能:
    如果我们使用单向链表的原代码,会发现忽略了打印尾结点,所以最后要加一个打印。
    考虑特殊情况,若这个单向循环链表为空链表呢?我们可以预先做个判断,若为空则直接返回,不进行任何操作。
    若只含有一个节点呢?直接看代码吧。
    def travel(self):
        """遍历链表"""
        cur = self.__head
        if self.is_empty():
            return 
        while cur != self.__head:
            print(cur.elem,end=' ')
            cur = cur.next
        print(cur.next,end=' ')

通过代码分析,若只含有一个节点,程序不会执行while循环,而是直接打印这个节点。

  • 实现头插法(add):
  1. 方法一
    这个主要是自己要理解
  2. 方法二

    这个方法比较容易理解,首先就是移动游标找到尾结点,当终止while循环的时候,游标cur所指向的位置恰好是尾结点,然后将添加的新节点node的node.next指向原首节点也就是self.__head,然后让self.__head指向node,最后将尾结点的next,指向我们新添加的这个头节点,即cur.next指向node或者也可以指向self.__head,因为此时self.head就指向node。
    考虑一下特殊情况,当链表为空链表时,那么self.__head指向的便是None,cur就在None的位置了,但是None怎么可能会有next呢?显然程序无法满足空链表的头插需求;现在考虑一下只有一个节点的链表是否符合要求呢?显然符合要求;下面是代码实现。

  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
            node.next = self.__head
            self.__head = node
            cur.next = node
  • 实现尾插法:
  1. 方法一
    这个应该不难理解
  2. 方法二
    这个也不难理解

    那我们直接上代码吧:

    def append(self, item):
        """尾部添加节点"""
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = node
        else:
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            cur.next = node
            node.next = self.__head

验证一下,若单向循环链表只有一个节点怎么办?是不是程序依旧可以实现啊。

  • 实现随机插入的(insert)方法:

    我们直接先码一下,单向链表的代码,看看怎么更改

    因为随机插入涉及的头插和尾插都是调用,所以我们这里就不在更改,因为已经可以实现;唯一需要更改的就是else语句,也就是涉及到中间插入的问题,但是单向循环链表的中间插入和单向链表的中间插入并没有什么区别啊,所以更无需更改。所以整体同单向链表一致,无需再做任何更改。
  • 实现查找某个元素的功能:
    单向链表

    我们直接从这个单向链表中更改:
    while语句的条件存在问题,要改成while cur.next != self.head
    这样一来if条件判断到最后一个元素的时候,就会终止循环了,而不再进行判断,其次还需要考虑的问题是特殊情况,比如空链表或者仅有一个节点的情况(直接上代码,按照代码进行分析)。

    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
        if cur.elem == item:
            return True
        return False

我们考虑一下,单个节点,代码也完全可以实现预期目标。

  • 实现删除节点的功能:

    观察代码,不能拿发现这个删除首节点的情况是最复杂的,因为涉及要遍历到尾节点,然后改变尾节点的指向。如果是删除中间节点的话,首尾节点无需更改,直接更改中间节点的指向即可。但同时当cur指向尾节点的时候,会忽略尾节点的判断,所以最后要重新判断一下尾节点的问题。接下来就是考虑首届点删除的问题了。
    还要考虑特殊情况:
  1. 判断是否为空链表,若为空直接返回。
  2. 如果仅有一个节点,那么程序直接跳出while循环,执行pre.next但pre指向的是None没有next ,需要让head直接指向None。
    总程序如下:
   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
                    self.__head = cur.next
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:#在中间删除
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next
        if cur.elem == item:#退出循环cur指向尾节点,在尾部删除
            if cur == self.__head:#链表只有一个节点
                self.__head = None
        else:
            pre.next = cur.next

总体代码:

class Node():
   '''节点'''
   def __init__(self,elem):
       self.elem = elem
       self.next = None

class SingleCycleLinkList(object):
   '''单向循环链表'''
   def __init__(self,node=None):
       #内部私有函数,链表头的初始化,可以直接建立空链表
       self.__head = node
       if node:
           node.next = node#self.__head指向node,如果node存在那还需要建立一个回环,让  note.next指向自己本身

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

   def length(self):
       """返回链表的长度"""
       #cur游标,用来移动遍历节点
       #count,用来记录节点数量
       count = 1
       if self.is_empty():
           return 0
       cur = self.__head
       while cur.next != self.__head:#满足仅有一个节点的选项
           count += 1
           cur = cur.next
       return count

   def travel(self):
       """遍历链表"""
       cur = self.__head
       if self.is_empty():
           return
       while cur != self.__head:
           print(cur.elem,end=' ')
           cur = cur.next
       print(cur.next,end=' ')

   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
           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 = self.__head
       else:
           cur = self.__head
           while cur.next != self.__head:
               cur = cur.next
           cur.next = node
           node.next = self.__head

   def insert(self, pos, item):
       """在指定位置添加节点"""
       pre = self.__head
       count = 0
       if pos <= 0:
           self.add(item)
       elif pos >= (self.length()-1):
           self.append(item)
       else:
           while count < (pos-1):
               count += 1
               pre = pre.next
           node = Node(item)
           node.next = pre.next
           pre.next = node

   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
                   self.__head = cur.next
                   while rear.next != self.__head:
                       rear = rear.next
                   self.__head = cur.next
                   rear.next = self.__head
               else:#在中间删除
                   pre.next = cur.next
               break
           else:
               pre = cur
               cur = cur.next
       if cur.elem == item:#退出循环cur指向尾节点,在尾部删除
           if cur == self.__head:#链表只有一个节点
               self.__head = None
       else:
           pre.next = cur.next


   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
       if cur.elem == item:
           return True
       return False



if __name__ == '__main__':
   li = SingleCycleLinkList()
   print(li.is_empty())
   print(li.length())

   li.append(1)
   li.append(2)
   print(li.is_empty())
   print(li.length())

   li.append(3)
   li.append(4)
   li.add(10)
   li.add(20)
   li.insert(2,30)
   li.insert(10,1000)
   li.insert(0,999)
   li.travel()
   print()
   print(li.search(20))
   print(li.search(123))
   li.travel()
   li.remove(999)
   li.travel()
   li.remove(1000)
   li.travel()
   li.remove(30)
   li.travel()

测试结果:

D:\anaconda\python.exe D:/bilibili大学/简书代码/singe_cycle_link_list.py
True
0
False
2
<__main__.Node object at 0x000001C2CEDBB390> 
True
False
<__main__.Node object at 0x000001C2CEDBB390> <__main__.Node object at 0x000001C2CEDBB438> <__main__.Node object at 0x000001C2CEDBB438> <__main__.Node object at 0x000001C2CEDBB438> 
Process finished with exit code 0
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 有头链表(注意:头结点有的地方是全局变量) 初学者学自于大话数据结构,不足及错误的地方请读者提出来,谢谢。 可加 ...
    lxr_阅读 741评论 0 2
  • 搞懂单链表常见面试题 Hello 继上次的 搞懂基本排序算法,这个一星期,我总结了,我所学习和思考的单链表基础知识...
    醒着的码者阅读 4,524评论 1 45
  • 摘自《维基百科》 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储...
    ChinaChong阅读 1,645评论 0 52
  • 芃芃棫朴,薪之槱之。济济辟王,左右趣之。 济济辟王,左右奉璋。奉璋峩峩,髦士攸宜。 淠彼泾舟,烝徒楫之。周王于迈,...
    尊敬的王二阅读 779评论 9 14
  • 有人把冲动比作魔鬼,其实不然,一瞬间的冲动也许会幻成最美的风景。 小时候总是在想,这个世界太美好太大太繁华,美...
    段小段姑娘阅读 240评论 0 0