单链表的一个变形是单向循环链表, 链表的最后一个节点的next域不再为None, 而是指向链表的头节点.
单向循环链表如图所示:
同样单向循环链表也是要使用python来对它的基本功能进行一个封装. 总体大致的功能如下:
注意: 区别单链表的操作如图:(图为单链表操作)
单向循环链表的操作多了一个尾部指向头部的链接.
事先定义一个节点, 包含数据元素的本身和它 的next区域的指向None.
class Node(object): '''节点 ''' def __init__(self, item): self.item = item self.next = None
结果如下(还是那句话, 写完一个功能调试一下):
同样需要事先初始化节点, 其实就是对之前的单链表的功能进行直接的更改, 可以直接把之前的代码复制过来,看看是否可以满足单向循环链表的的功能, 如果可以直接过去就好, 如果不行重新修改. (注意和之前单链表的区别, 循环的终止点, 设置循环的终止, 到哪里才算是一次循环的完成)
class SinCycLinkedlist(object): ''' 单向循环链表 ''' def __init__(self): self.__head = None def is_empty(self): ''' 判断链表是否为空 ''' def length(self): ''' 返回链表的长度 ''' def travel(self): ''' 遍历链表 ''' def add(self, item): ''' 头部添加节点 ''' def append(self, item): ''' 尾部添加节点 ''' def insert(self, pos, item): ''' 指定位置添加节点 ''' def remove(self, item): ''' 删除节点 ''' def search(self, item): ''' 查找节点是否存在 '''if __name__ == "__main__": ll = SinCycLinkedlist()
基本功能大致如上.
这功能和之前的单链表是一样的, 只需要判断头节点是否为空, 直接返回True or False就好了.
def is_empty(self): ''' 判断链表是否为空 ''' return self.__head == None
通过循环遍历来计算元素的个数, 没遍历一个count就加1, 但是这里的循环的终止条件, 要变, 不能使用之前的. 终止条件改为 cur.next != self.__head 直接判断最后一个节点的下一个区域是否指向头结点, 如果是结束一次循环, 如果不是继续往后遍历.代码如下:
def length(self): ''' 返回链表的长度 ''' if self.is_empty(): return 0 count = 1 cur = self.__head while cur.next != self.__head: count += 1 cur = cur.next return count
同样是和之前的单链表的是一样的, 只是循环的条件得改掉, 由于是头尾相连的, 导致之前的cur != None 在非空链表中不可以使用每个元素都是有值的, 没有指向None的元素. 每个元素的next区域都有指向, 每个元素cur.next != None也是不可以使用的.所以还是改成cru.next != self.__head以最后一个节点和头节点作为比较.代码如下:
def travel(self): ''' 遍历链表 ''' if self.is_empty(): return cur = self.__head print (cur.item) # 头节点没有参与循环, 要直接打印出来 while cur.next != self.__head: cur = cur.next print (cur.item) print ("") # 换行
先定义要添加的节点node, 判断是否为空, 如果是空的话, 直接按照头结点的添加, 头节点指向node, node的next区域指向头节点.如果不是, 添加的节点指向__head, 移到链表尾部, 将结尾部节点的next指向node. 如代码:
def add(self, item): ''' 头部添加节点 '''def travel(self): ''' 遍历链表 ''' if self.is_empty(): return cur = self.__next print (cur.item) # 头节点没有参与循环, 要直接打印出来 while cur.next != self.__head: cur = cur.next print (cur.item) print ("") # 换行def travel(self): ''' 遍历链表 ''' if self.is_empty(): return cur = self.__next print (cur.item) # 头节点没有参与循环, 要直接打印出来 while cur.next != self.__head: cur = cur.next print (cur.item) print ("") # 换行 node = Node(item) if self.is_empty(): self.__head = node node.next = self.__head else: # 添加的节点指向__head node.next = self.__head # 移到链表的尾部, 将尾部节点的next指向node cur = self.__head while cur.next != self.__head: cur = cur.next cur.next = node # __head 指向添加node的 self.__head = node
和之前的单链表差不多, 判断是否是空链表, 如果是头节点指向node, node的next区域指向self.__head, 如果不是, 移动到链表的尾部, 注意循环结束的条件cur.next != self.__head , 找到尾节点之后将尾节点指向node, 再将node指向头节点__head, 注意指向的先后顺序, 先是cur.next指向再是node的next指向, 注意区分先后顺序, 每种指向的区别, 先后的影响. 代码如下:
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 # 将尾节点指向node cur.next = node # 将node的指向头结点__head node.next = self.__head
区别单链表的尾部添加节点, 区别注意尾部的指向问题. 单链表尾部如图所示:
基本思路和前面的单链表一样.先判断插入的位置. 如果是头部插入直接调用self.add()函数就可以 ( 这里使用pos<=0来表示头部的插入, 传递进来的参数小于0了, 就认为他是要在头部进行插入 ) , 如果是尾部直接调用前面的self.append()函数就好 ( 使用pos > self.length - 1 来表示在尾部插入传递进来的参数, 要求的位置超过了链表应有的长度, 就认为直接在尾部进行插入 ) . 注意pos参数传递过来, 判断插入的位置的时候注意一定要区别和链表本身的长度之间的区别, 是加一还是减一. 指定其他位置的插入, 使用count来计数, 如果count < pos - 1 接着向后移动就可以了 , 如果不满足条件了, 注意节点插入的先后顺序. 思考为什么是count < pos - 1 而不是正好等于或者加一. 详细代码如下:
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 = cur.next cur.next = node
注意node的插入的先后顺序
这里需要引入pre游标来辅助我们判断节点, 对节点进行删除.
判断链表是否为空, 如果是直接返回, 空链表不需要删除. 如果头结点的元素就是要查找的元素item, 进入分支判断, 如果链表不止一个节点, 先找到尾节点, 将尾节点的next指向第二个节点(注意这些节点之间next区域移动的先后顺序, 注意之间的区别). 如果链表只有一个节点该怎么办.
第一个节点不是要删除的, 先找到要删除的元素, 再通过区域的指向来进行删除. 代码如下:
def remove(self, item): ''' 删除节点 ''' # 若链表为空 if self.is_empty(): return # 将cur 指向头节点 cur = self.__head pre = None # 若头节点就是要找的 if cur.item == item: # 如果链表不止一个节点 if cur.next != self.__head: # 先找到尾节点, 将尾节点的next指向第二个节点 while cur.next != self.__head: cur = cur.next # cur指向了尾节点 cur.next = self.__head.next self.__head = self.__head.next else: # 链表只有一个节点 self.__head = None else: pre = self.__head # 第一个节点不是要删除的 while cur.next != self.__head: # 找到了要删除的元素 if cur.item == item: # 删除 pre.next = cur.next return else: pre = cur cur = cur.next # cur指向尾节点 if cur.item == item: # 尾部删除 pre.next = cur.next
这个功能和单链表中的差不多就是一个循环判断的条件不一样, 注意新的判断条件是cur的next区域是否等于头节点.详细代码如下:
def search(self, item): ''' 查找节点是否存在 ''' if self.is_empty(): return False cur = self.__head if cur.item == item: return True while cur.next != self.__head: cur = cur.next if cur.item == item: return True return False
if __name__ == "__main__": ll = SinCycLinkedlist() ll.add(1) ll.add(2) ll.append(3) ll.insert(2,4) ll.insert(4,5) ll.insert(0,6) print ("length:",ll.length()) ll.travel() print (ll.search(3)) print (ll.search(7)) ll.remove(1) print ("length:", ll.length()) ll.travel()
运行结果如下:
上传代码之后, 缩进可能会有点小问题, 注意一定要注意缩进
当一个IT组织开始走到需要实施网络边缘的旅程时,他们很快意识到面对的挑战与他们在传统数据中心内所经历的挑战不同。 第一个挑战是空间。与更大的核心或区域数据中心同类产品相比,许多边缘站点的物理尺寸更小,因此,需要仔细计划好,尝试在未为其专门设计的空间中安装硬件。 第二个挑战是运行环境。还必须解决的可能面对的冷热温度变化 ,天气,无...
题目: 二叉搜索树与双向链表 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。 为了让您更好地理解问题,以下面的二叉搜索树为例: 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一...
题目:删除链表的节点 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。 注意:此题对比原题有改动 示例 1: 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为...
【从零开始的ROS四轴机械臂控制】(一)- 实际模型制作、Solidworks文件转urdf与rviz仿真 一、模型制作 1.实际模型制作 2.Solidworks模型制作 二、Solidworks文件转urdf 1.sw_urdf_exporter插件 2.添加坐标系和转轴 3.导出urdf文件 三、rivz仿真...
题目:复杂链表的复制 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。 示例 1: 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出...
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 你应当保留两个分区中每个节点的初始相对位置。 示例: 输入: head = 1->4->3->2->5->2, x = 3 输出: 1->2->2->4->3->5 使用双指针的方式,各自构造一个大元素的头节点和小元素...
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 说明:不允许修改给定的链表。 示例 1: 输入:head = [3,2,0,-4], pos = 1...
题目描述如下: 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 说明: 1 ≤ m ≤ n ≤ 链表长度。 示例: 输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL 很明显这个题目是206 反转链表的进阶版 需要记录第m-1个节点和第n+1个...
描述如下: 反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 方法一:原地反转 数据结构如下 struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}...
基于KCF和MobileNet V2以及KalmanFilter的摄像头监测系统 简介 这是一次作业。Tracking这一块落后Detection很多年了,一般认为Detection做好了,那么只要能够做的足够快,就能达到Tracking的效果了,实则不然,现在最快的我认为就是一些可以在手机等arm下使用的轻量神经网络了,但是其牺牲...