数据结构-链表-双向链表
单向链表和环形链表都是属于拥有方向性的链表,只能单向遍历,如果由于某种原因造成了某个连接断裂,那后面的链表数据便会遗失而无法复原。所以,我们可以将两个方向不同的链表结合起来,除了存放数据的字段之外,它还有两个指针变量,除了类似于单向链表的下一个指针next外,还需要一个指针指向上一个数据,这样的链表就是双向链表(Double Linked List)
由于每个节点都有两个指针,可以双向通行,因此可以轻松地找到前后节点,同时从链表中任意的节点都可以找到其他节点,而不需要经过反转或者对比节点等处理,执行速度较快。
-
双向链表的建立
双向链表的数据结构中,对于每个节点来说,具有3个字段,两个指针变量,一个数据字段,指针变量分别指向左右(前后)指针,使用llink和rlink表示,llink指向上一个节点(可以看做是left link),rlink指向下一个节点(可以看做right link)
llink data rlink 指向上一个节点 节点 指向下一个节点 实际情况中,双向链表可以是环形的,也可以不是环形的,如果最后一个节点的右指针指向了首节点,而首节点的左指针指向尾节点,这样的链表就是环形双向链表
class student: def __init__ (self): self.name = '' self.no = 0 self.llink = None self.rlink = None head = student() #声明头指针 head.llink = None #头指针的左指针指向None head.rlink = None #头指针的右指针指向None ptr = head #设置存取指针开始的位置 select = 0 while True: select = int(input('(1) 新增 (2) 离开')) if select == 2: break if select == 1: new_data = student() new_data.name = input('请输入姓名:') new_data.no = input('请输入学号:') ptr.rlink = new_data #右指针指向new_data new_data.llink = ptr #新节点的左指针指向ptr new_data.rlink = None #新节点的右指针设置为None ptr = new_data #指针设置为新元素的位置
-
双向链表的遍历
双向链表因为有两个指针,所以可以双向遍历,在单向链表中如果想要逆向遍历就需要反转链表才可以实现,而在双向链表中可以根据llink和rlink来进行双向遍历
-
从左向右遍历(使用rlink)
ptr = head.rlink while ptr != None: print(ptr.name,ptr.no) ptr = ptr.rlink #指针右移
-
从右向左遍历(使用llink)
ptr = head.rlink while ptr != None: ptr = ptr.rlink #找到最右侧的节点 while ptr != head: print(ptr.name,ptr.no) ptr = ptr.llink #指针左移
-
-
双向链表插入新节点
双向链表的节点插入可以分为三种情况
-
将新节点加入双向链表的第一个节点之前:将新节点的右指针(rlink)指向原链表的第一个节点,接着将原链表第一个节点的左指针(llink)指向新节点,将原链表的链表头指针指向新节点
X head rlink 插入的节点(新head) 链表原来的第一个节点 下一个节点 X.rlink = head head.llink = X head = X
-
将新节点加入双向链表的末尾:将原链表的最后一个节点的右指针指向新节点,将新节点的左指针指向原链表的最后一个节点,并将新节点的右指针指向None
llink Ptr X 上一个节点 原链表的尾节点 新节点 ptr.rlink = X X.llink = ptr X.rlink = None
-
将新节点加入链表中的ptr节点之后:首先将ptr节点的右指针指向新节点,再将新节点的左指针指向ptr节点,接着将ptr节点的下一个节点的左指针指向新节点,最后将新节点的右指针指向ptr的下一个节点
ptr X ptr.rlink 原链表的上一个节点 新节点 原链表的下一个节点 ptr.rlink.llink = X X.rlink = ptr.rlink X.llink = ptr ptr.rlink = X
注意:此次插入的过程中出现的三个变量互换,一定要注意互换的前后顺序,如果先ptr.rlink = X,就会出现ptr.rlink再使用时指向的是X,而不是原链表的下一个节点
-
-
双向链表删除节点
双向链表的删除节点和单向链表的删除节点相似,也可以分为三种情况
-
删除双向链表的第一个节点:将链表头指针head指向原链表的第二个节点,再将新链表头的左指针指向None
head head.rlink … 原链表的第一个指针 新链表的head … head = head.rlink head.llink = None
-
删除双向链表的最后一个节点:将原链表最后一个节点之前的一个节点的右指针指向None即可
… end.llink end … 新链表最后一个节点 原链表最后一个节点 end.llink.rlink = None
-
删除双向链表的中间节点X:将X节点的前一个节点的右指针指向X节点的下一个节点,再将X节点的下一个节点的左指针指向X节点的上一个节点
X.llink X X.rlink 上一个节点 删除的中间节点 下一个节点 X.llink.rlink = X.rlink X.rlink.llink = X.llink
-