单链表宇宙超级无敌完全(Python实现)

初步使用链表

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 功能:
# 创建空表 删除表 判断表是否为空 判断表是否满 
# 首插 尾插 一般情况插入 
# 首删 尾删 一般情况和删
# 扫描、查找和遍历    1、按元素查找2、按下标查找
class LNode:    # 表节点类
    def __init__(self, elem, next_ = None):
        self.elem = elem
        self.next = next_

# 创建空链表
# head = LNode(None)

# 创建表头(创建链表)
head = LNode(0) #  head不变,需要使用的时候用一个中间变量(指针或游标)引用他

# 创建一些节点
pre = head
for i in range(1,10):
    # node = LNode(i)
    # pre.next = node
    pre.next = LNode(i)
    pre = pre.next
    # if i == 9:
    #     node.next = None

# 按下标定位,首节点下标为0
p = head
i = 5
while p is not None and i>0: 
    i = i-1     # 当i=1时执行最后一次循环,最后i=0
    p = p.next  
print('下标为5的元素:',p.elem)

p = head
for i in range(5):  # 打印下标为5的元素(第6个元素)
    if p is not None:
        p = p.next
print('下标为5元素:',p.elem)

# 按元素定位
p = head
while p is not None and (p.elem != 5):   # 打印节点元素为5的元素
    p = p.next
else:
    print('查询节点元素为5的元素:',p.elem)

# 头插:插在表头的前面(原来的head前面)
q = LNode(100)
q.next = head
head = q

# 遍历:打印所有节点
print('遍历:以下打印链表所有节点:')
p = head
while p is not None: # 节点存在就打印出节点元素
    print(p.elem) 
    p = p.next

# 求表长度: 表头+表节点+表尾
def length(head):
    p = head; cnt = 0 #计数习惯初始为0
    while p is not None: # p is None表示这个节点不存在,判断尾节点:p.next is None
        cnt = cnt + 1 # p is not None就加1
        p = p.next
    return cnt 

length = length(head)
print('链表长度为:',length)



# 头插,头插是插在head前面
# q = LNode(0)
# q.next = head
# head = q

# 中间插入:让游标pre指向待删除节点的前一节点、  即使pre指向的是尾节点可可以
# q = LNode(13)
# q.next = pre.next
# pre.next = q # 注意: 该语句不能和上一条语句顺序互换,如果先执行该条语句,链表插入位置的后面部分会被Python回收机制回收

# 尾插, 要先遍历一遍链表找到尾节点
# node = LNode(29)
# pre = head
# while  pre.next is not None:
#     pre = pre.next # 游标向后移动一位
# else:   
#     pre.next = node
#     node.next = None

#头删
# head = head.next

#一般删: pre指向需要删除节点的前一节点
# pre.next = pre.next.next

# 查找、遍历:对表中一切元素的检查都要从表头变量head开始
# p = head
# while p is not None ''' and (其他条件)''':
#     '''对p所指节点的操作'''
#     p = p.next #游标p向后移动一位


# 链表复杂度分析:

单链表

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class LinkListUnderflow(ValueError): # 自定义异常类
    pass


class LNode:    # 表节点类(重要概念) -->该类的一个对象表示一个节点
    def __init__(self, elem, next_ = None):
        self.elem = elem
        self.next = next_

# 初始化一个链表玩一下
# list1 = LNode(1)
# p = list1
# for i in range(2,11):
#     p.next = LNode(i) # 一边循环,一边新增节点,同时让指针指向新增节点
#     p = p.next
# 打印每个元素出来看一下
# p = list1   
# while p is not None:
#     print(p.elem) 
#     p = p.next



###################
'''   单链表    '''
###################
# 节点类和单链表对象类的区别:
#   节点类:一个属性表示一个数据域或者指针域
#   单链表对象类:一个属性表示一个对象,这个对象是节点类实例化的对象,即一个节点
# 节点类实例化后的对象表示 --> 节点
# 单链表对象类实例化后的对象表示 -->  链表--汇集对象
class LList:    # 单链表对象类(重要概念) -->该类的属性是表节点类的对象
    def __init__(self):
        self._head = None # 这个是表头,表头代表链表,表头地址即表示链表地址,和数组一样:数组的地址就是第一个元素的地址
    
    def is_empty(self):
        return self._head is None

    # 头插
    def prepend(self, elem):
        # p = LNode(elem) # 创建新的节点对象p
        # p.next = self._head
        # self._head = p    # 注释的这三行等价于下面一行
        self._head = LNode(elem,self._head)     # ???使用LNode类

    #追加到表尾
    def append(self, elem):
        # 空表:一个节点都不存在,包括表头、中间节点、尾节点
        if self._head is None: # 如果是空表直接插在头结点后面,结束
            self._head = LNode(elem)
            return
        p = self._head
        while p.next is not None:
            p = p.next
        p.next = LNode(elem) # 表尾节点指向新创建的节点
    
    # 插入中间节点
    def insert(self, index, elem):
        if (self._head is None) and (self._head.next is None):
            raise LinkListUnderflow("in insert")
        p = self._head
        while p is not None and index>1: 
            index = index-1   
            p = p.next
        node = LNode(elem)
        node.next = p.next # 将新增节点先连上链表
        p.next = node # 断开前一节点,将前一节点指向新增节点  
        ###注意:一定要先连再断,如果先断开前一节点,Python回收机制会将该节点后的的部分回收,相当于删除了链表后面部分

    # 弹出表头元素
    def pop(self):
        if self._head is None:
            raise LinkListUnderflow('in pop')
        e = self._head.elem
        self._head = self._head.next
        return e

    # 弹出表尾元素
    def pop_last(self):
        if self._head is None: # 空表,一个节点也没有,在内存中为空
            raise LinkListUnderflow('in pop_last')
        p = self._head
        if p.next is None: # 表中只有一个元素,既是表头也是表尾
            e = p.elem
            self._head = None
            return e
        while p.next.next is not None:
            p = p.next
        e = p.next.elem
        p.next = None
        return e

    # 删除表中第一个元素为elem的节点
    def remove_any(self, elem): #两个游标,cur用来寻找elem,pre始终指向cur的前一个节点,待执行删除的时候用pre指向cur的后一节点
        pre = None
        cur = self._head
        while cur is not None:
            if cur.elem == elem:
                if pre is None: # cur是头结点
                    self._head = cur.next # head指向原头结点的下一个节点
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next
        else:
            raise LinkListUnderflow('in remove_any')
    
    # 删除所有元素为elem的节点
    def remove_elem_all(self,elem):
        pre = None
        cur = self._head
        while cur is not None:
            if cur.elem == elem:
                if pre is None:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                cur = pre.next # 将cur指向删除节点的下一个节点
            else:
                pre = cur
                cur = cur.next
        
    def remove_any2(self, elem): # 一定要有一个游标指向待删除节点的前一个节点
        if self._head == None:
            raise LinkListUnderflow('in remove_any2')
        if self._head.elem == elem:
            self._head = self._head.next
            return
        p = self._head
        while p is not None and (p.next.elem != elem):
            p = p.next
        else:
            p.next = p.next.next 
    
    def remove_index(self,index):
        pre = self._head
        while pre is not None and index>1: # 让p指向待删除节点的前一节点
            index = index-1     
            pre = pre.next  
        pre.next = pre.next.next

    # 按照元素查询
    def find(slef, elem):
        p = self._head
        while p is not None:
            if p.elem == elem:
                return p.elem
            p = p.next

    # 按照下标查询
    def find_index(self, index):
        p = self._head
        while p is not None and i>0: 
            i = i-1     
            p = p.next  
        return p.elem
    
    def find_first(self):
        pass # 略
    
    def find_last(self):
        pass # 略

    # 遍历输出所有元素
    def printall(self):
        p = self._head
        while p is not None:
            print(p.elem,  end='')
            if p.next is not None:
                print(', ', end='')
            p = p.next
        print('')

    # 遍历执行某种操作proc
    # proc的实参是可以作用于表元素的操作函数,它将作用于表的每一个元素,这里以打印为例
    # proc常常可以用一个lambda表达式来定制
    def for_each(self, proc):
        p = self._head
        while p is not None:
            proc(p.elem)
            p = p.next
    
    # 定义迭代器
    def elements(self):
        p = self._head
        while p is not None:
            yield p.elem
            p = p.next
    
    # 筛选生成器,相比于定义迭代器,它加上了一个筛选的函数pred,我们把这个pred
    def find_filter(self,pred):
        p = self._head
        while p is not None:
            if pred(p.elem):
                yield p.elem
            p = p.next
    # 用于测试pred的方法 -->输出偶数
    def is_oddnumber(self,em):
        if em % 2 == 0:
            return True
        else:
            return False

    # 反转链表
    def reverse(self):
        pre = None
        cur = self._head
        while cur is not None:
            q = cur
            cur = q.next # 游标cur向后移动
            q.next = pre # 每次更改p节点的指向
            pre = q # 游标pre向后移动
        self._head = pre
        # 这里也可以不引入cur,全部用self._head替换,表示表头不断向后移动

# mylist = LList()
# for i in range(10):
#     mylist.prepend(i)
# for i in range(11,20):
#     mylist.append(i)
# mylist.prepend(10)

# mylist.insert(3,300)
# mylist.insert(4,300)
# mylist.insert(7,300)
# mylist.insert(8,400)
# mylist.insert(9,400)
# mylist.insert(11,400)
# mylist.remove_any(300)
# mylist.remove_elem_all(400)

# mylist.remove_index(1)

# mylist.printall()
# mylist.reverse() 
# mylist.printall()

# mylist.for_each(print) #以打印为例

# for x in mylist.elements():
#     print(x)

# for x in mylist.find_filter(mylist.is_oddnumber):
#     print(x)

单链表加上尾节点引用域

# 增加尾节点引用域
# 除了操作表头和表尾不一样,其他方法都一样可以使用
# 类设计要遵循内在的一致性
class LList1(LList):
    def __init__(self):
        LList.__init__(self) # 继承父类LList的初始化函数 
        self._rear = None # 尾节点引用域
        # self._head = None # head就是指向链表对象的引用,链表的头结点所在的地址表示链表的地址,相当于数组
    
    def prepend(self, elem):
        if self._head is None:
            self._head = LNode(elem, self._head)
            self._rear = self._head
        else:
            self._head = LNode(elem, self._head)
    
    def append(self,elem):
        if self._head is None:
            self._head = LNode(elem, self._head)
            self._rear = self._head # 这里_head的指针域是自己,这就等于_rear指向了尾节点 
        else:
            self._rear.next = LNode(elem)
            self._rear = self._rear.next
    
    def pop_last(self):
        if self._head is None:
            raise LinkListUnderflow('in pop_last')
        p = self._head
        if self._head.next is None:
            e = p.elem
            self._head = None
            return e
        while p.next.next is not None: # 把p.next看成一个节点在移动、或者判断循环终止的时候p是指哪一个节点
            p = p.next
        e = p.next.elem # 此时p.next是指尾节点
        p.next = None
        self._rear.next = p
        return e

# mylist2 = LList1() 
# mylist2.prepend(99)
# for i in range(1,10):
#     mylist2.append(i)
# for x in mylist2.find_filter(lambda y: y%2 == 1):
#     print(x)
# mylist2.pop_last()

循环单链表

# 单链表加上尾节点引用域:表尾查找和追加O(1),删除O(n)。因为删除需要通过遍历找到尾节点的前一个节点
# 循环单链表:表尾查找和追加O(1),删除O(n)
# 链表对象用来记录表尾节点更合适
# 循环单链表与普通单链表的差异:1、循环遍历的结束控制 2、没有表头引用域,所以单链表涉及表头的方法这里不能继承使用
class LCList: # 循环单链表类
    def __init__(self):
        self._rear = None #尾节点引用域

    def is_empty(self):
        return self._rear is None
    
    def prepend(self, elem):
        # p = LNode(elem)
        if self._rear is None:
            # p.next = p # 建立一个节点的环
            # self.-repr = p
            self._rear = LNode(elem)
            self._rear.next = self._rear
        else:
            # p.next = self._rear.next
            # self._rear.next = p
            self._rear.next = LNode(elem, self._rear.next)
        
    def append(self, elem):
        self.prepend(elem)
        self._rear = self._rear.next # 表尾改为追加的节点

    def pop(self):
        if self._rear is None:
            raise LinkListUnderflow("in pop")
        p = self._rear.next
        if self._rear is p:
            self._rear = None
        else:
            self._rear.next = p.next
        return p.elem
    
    def printall(self):
        if self.is_empty():
            return
        p = self._rear.next
        while True:
            print(p.elem, end=', ')
            if p is self._rear:
                break
            p = p.next

# mylist3 = LCList() 
# for i in range(1,10):
#     mylist3.prepend(i)
# for i in range(11,20):
#     mylist3.append(i)
# for x in mylist3.find_filter(lambda y: y%2 == 1):
#     print(x)
# mylist3.pop()
# mylist3.printall()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值