python学习笔记_第28天(线性表_链表2)

线性表

链表

双向链表

一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个前驱节点,当此节点为第一个节点时,指向空值;而另一个指向下一个后继节点,当此节点为最后一个节点时,指向空值。
在这里插入图片描述

双向链表的操作
操作说明
is_empty()链表是否为空
length()链表长度
travel()遍历链表
add(item)链表头部添加
append(item)链表尾部添加
insert(pos, item)指定位置添加
remove(item)删除节点
search(item)查找节点是否存在
双向链表操作具体实现
  • 指定位置插入节点
    在这里插入图片描述
  • 删除元素
    在这里插入图片描述
class DoubleNode:
    '''双向链表结点'''

    def __init__(self, item):
        self.item = item
        self.prev = None
        self.next = None


class DoubleLinkList:
    '''双向链表'''

    #  构造函数、判空、求长、遍历、查找与单链表相同,不涉及“前驱结点连接域”和“后继结点链接域”
    #  可以直接继承Single_link_list模块,实现代码复用

    def __init__(self, doublenode=None):
        self.__head = doublenode

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

    def length(self):
        """链表长度"""
        # 遍历计数
        cur = self.__head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历整个链表"""
        # 遍历打印
        cur = self.__head
        while cur != None:
            print(cur.item, end=' ')
            cur = cur.next
        print()

    def search(self, item):
        """查找节点是否存在,并返回True或者False"""
        cur = self.__head
        while cur != None:
            if cur.item == item:
                return True
            else:
                cur = cur.next
        else:
            return False

    # add、append、insert、remove与单链表有所差别

    def add(self, item):
        """链表头部添加元素,头插法"""
        doublenode = DoubleNode(item)
        doublenode.next = self.__head
        self.__head = doublenode
        doublenode.next.prev = doublenode  # 双向链表多一个指向前驱结点的链接域,指向上一个结点

    def append(self, item):
        """链表尾部添加元素,尾插法"""
        doublenode = DoubleNode(item)
        if self.is_empty():
            self.__head = doublenode
        else:
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            cur.next = doublenode
            doublenode.prev = cur  # 双向链表尾插法多指定一个前驱节点

    def insert(self, pos, item):
        """指定位置添加元素"""
        # cur.prev就可以指向前个结点,不用设定pre游标
        if pos <= 0:
            self.add(item)
        elif pos > (self.length() - 1):
            self.append(item)
        else:
            cur = self.__head
            count = 0
            while count < pos:
                count += 1
                cur = cur.next
            # 退出循环时此时cur指向pos位置
            doublenode = DoubleNode(item)
            doublenode.next = cur
            doublenode.prev = cur.prev
            cur.prev.next = doublenode
            cur.prev = doublenode

    def remove(self, item):
        """删除节点"""
        # 双向链表有前后两个链接域,则只需一个游标进行遍历
        cur = self.__head
        while cur != None:
            if cur.item == item:
                if cur == self.__head:
                    self.__head = cur.next
                    if cur.next:
                        # 考虑只有一个结点的特殊情况,此时cur.next指向None,None没有None.next,报错。
                        # 当cur.next为None,则if False跳过条件语句不报错
                        cur.next.prev = None
                else:
                    cur.prev.next = cur.next
                    if cur.next:
                        # 考虑在链表末尾添加结点的特殊情况,此时cur.next指向None,None没有None.next,报错。
                        # 当cur.next为None,则if False跳过条件语句不报错
                        cur.next.prev = cur.prev
                break
            else:
                cur = cur.next

测试

if __name__ == '__main__':
    dll = DoubleLinkList()
    print(dll.is_empty())
    print(dll.length())

    dll.append(1)
    print(dll.is_empty())
    print(dll.length())

    dll.append(2)
    dll.add(8)
    dll.append(3)
    dll.append(4)
    dll.append(5)
    dll.append(6)  # 8 1 2 3 4 5 6

    dll.insert(-1, 9)  # 索引为负,默认头部添加:9 8 1 2 3 4 5 6
    dll.travel()
    dll.insert(3, 100)  # 在3索引处添加,其余节点后移:9 8 1 100 2 3 4 5 6
    dll.travel()
    dll.insert(10, 200)  # 索引超出链表长度,默认尾部添加:9 8 1 100 2 3 4 5 6 200
    dll.travel()

    print(dll.search(100))
    dll.remove(100)  # 删除第一个匹配的节点:9 8 1 2 3 4 5 6 200
    dll.travel()
    print(dll.search(100))
    dll.remove(9)  # 删除头节点:8 1 2 3 4 5 6 200
    dll.travel()
    dll.remove(200)  # 删除尾节点:8 1 2 3 4 5 6
    dll.travel()

执行结果:
True
0
False
1
9 8 1 2 3 4 5 6
9 8 1 100 2 3 4 5 6
9 8 1 100 2 3 4 5 6 200
True
9 8 1 2 3 4 5 6 200
False
8 1 2 3 4 5 6 200
8 1 2 3 4 5 6

单向循环链表

单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
在这里插入图片描述

单向循环链表的操作
操作说明
is_empty()链表是否为空
length()链表长度
travel()遍历链表
add(item)链表头部添加
append(item)链表尾部添加
insert(pos, item)指定位置添加
remove(item)删除节点
search(item)查找节点是否存在
单向循环链表操作具体实现
class SingleCircleNode:
    """单向循环链表的结点"""

    def __init__(self, item):
        self.item = item
        self.next = None


class SingleCircleLinkList:
    """单向循环链表"""

    # 验证特殊情况空列表是否也成立
    def __init__(self, singlecirclenode=None):  # 构造单个节点的单向循环链表
        self.__head = singlecirclenode
        if singlecirclenode != None:  # 当不是空链表,单向循环列表需要连接循环
            singlecirclenode.next = singlecirclenode

    # 判空代码和单向链表相同
    def is_empty(self):
        """判断链表是否为空"""
        return self.__head == None

    def length(self):
        """链表长度"""
        # 遍历计数
        # 计数项count初始值调整为1后,空列表不成立,if判断另外考虑
        if self.is_empty():
            return 0
        else:
	        cur = self.__head
	        # 因为循环条件改成cur.next!=self.__head,当遍历到最后一个结点时不进入循环体,少一次计数,所以count初始值改为1
	        count = 1
	        # 因为cur的初始赋值为self.__head,所以循环判断条件只能选cur.next!=self.__head
	        while cur.next != self.__head:
	            count += 1
	            cur = cur.next
	        return count

    def travel(self):
        """遍历整个链表"""
        # 遍历打印
        cur = self.__head
        # 当为空链表时None.next报错
        if cur == None:
            return
        else:
            while cur.next != self.__head:
                print(cur.item, end=' ')
                cur = cur.next
            # 退出循环时cur指向尾结点,但尾结点未进入循环体打印,需单独打印
            print(cur.item)

    def add(self, item):
        """链表头部添加元素,头插法"""
        # 由于尾结点指针需指向头,所以头插法也要进行遍历
        singlecirclenode = SingleCircleNode(item)
        cur = self.__head
        # 当链表为空,None.next报错
        if self.is_empty():
            self.__head = singlecirclenode
            singlecirclenode.next = singlecirclenode
        # 当链表只有单个结点也成立
        else:
            while cur.next != self.__head:
                cur = cur.next
            # 退出循环时cur指向尾结点
            singlecirclenode.next = self.__head
            self.__head = singlecirclenode
            cur.next = singlecirclenode  # 尾结点链接指向头部

    def append(self, item):
        """链表尾部添加元素,尾插法"""
        singlecirclenode = SingleCircleNode(item)
        # 特殊情况,链表为空
        if self.is_empty():
            self.__head = singlecirclenode
            singlecirclenode.next = singlecirclenode
        # 特殊情况,只有单个结点也成立
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            cur.next = singlecirclenode
            singlecirclenode.next = self.__head

    # 除pos <= 0和pos > (self.length() - 1)的特殊情况外,链表中间插入结点不涉及尾结点的链接循环,与单链表相同
    def insert(self, pos, item):
        """指定位置添加元素"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length() - 1):
            self.append(item)
        else:
            # 游标pre控制指定位置的前一节点的next属性
            pre = self.__head
            count = 0
            # 当循环体退出后,要求pre指向pos-1位置
            while count < (pos - 1):
                count += 1
                pre = pre.next
            singlecirclenode = SingleCircleNode(item)
            singlecirclenode.next = pre.next
            pre.next = singlecirclenode

    def remove(self, item):
        """删除节点"""
        # 当删除的结点为头结点或尾结点时会影响单向循环链表的链接域,删除中间结点与单链表相同
        if self.is_empty():
            return
        cur = self.__head
        pre = None  # 与游标cur相隔一个节点
        while cur.next != self.__head:
            if cur.item == item:
                if pre == None:  # 找到需删除的结点,且为头节点
                    # 需要新建游标,遍历找尾结点
                    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
        # 尾结点不进入循环,单独判断尾结点是否符合
        if cur.item == item:
            if cur==self.__head:  # 通过判断cur是否移动,来确定是否只有单个结点
                # 链表中只有一个需删除的节点,单个结点既是头结点又是尾结点,尾结点不进循环体
                self.__head=None
            else:  
                # 当尾结点是唯一结点时,pre=None,None.next报错
                pre.next = cur.next

    def search(self, item):
        """查找节点是否存在,并返回True或者False"""
        if self.is_empty():  # 空链表,None.next会报错
            return False
        else:
            cur = self.__head
            while cur.next != self.__head:  # 处理未进入循环的尾部结点
                if cur.item == item:
                    return True
                else:
                    cur = cur.next
            if cur.item == item:
                return True
            else:
                return False

测试

if __name__ == '__main__':
    ll = SingleCircleLinkList()
    print(ll.is_empty())
    print(ll.length())

    ll.append(1)
    print(ll.is_empty())
    print(ll.length())

    ll.append(2)
    ll.add(8)
    ll.append(3)
    ll.append(4)
    ll.append(5)
    ll.append(6)  # 8 1 2 3 4 5 6

    ll.insert(-1, 9)  # 索引为负,默认头部添加:9 8 1 2 3 4 5 6
    ll.travel()
    ll.insert(3, 100)  # 在3索引处添加,其余节点后移:9 8 1 100 2 3 4 5 6
    ll.travel()
    ll.insert(10, 200)  # 索引超出链表长度,默认尾部添加:9 8 1 100 2 3 4 5 6 200
    ll.travel()

    print(ll.search(100))
    ll.remove(100)  # 删除第一个匹配的节点:9 8 1 2 3 4 5 6 200
    ll.travel()
    print(ll.search(100))
    ll.remove(9)  # 删除头节点:8 1 2 3 4 5 6 200
    ll.travel()
    ll.remove(200)  # 删除尾节点:8 1 2 3 4 5 6
    ll.travel()

执行结果:
True
0
False
1
9 8 1 2 3 4 5 6
9 8 1 100 2 3 4 5 6
9 8 1 100 2 3 4 5 6 200
True
9 8 1 2 3 4 5 6 200
False
8 1 2 3 4 5 6 200
8 1 2 3 4 5 6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值