用python3实现数据结构中的单向链表single linked list

单向链表简称单链表,是链表中最简单的一种形式,单链表的每个节点包含两个域(首位相连的两部分内容),一个信息域(或叫元素域,用来存放具体数据)和一个链接域。这个链接域中存放的链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值(None)。而每个单链表都有一个隐式的head节点(self.__head),这个head节点不存放具体数据因而没有信息域,也无法从外部访问,只有一个链接域用来指向第一个存放数据的链表节点(也就是平常所说的显式的头节点)。

单链表类主要包含以下基本操作:

  • is_empty() 链表是否为空
  • length() 链表长度
  • travel() 遍历整个链表
  • add(item) 链表头部添加元素
  • append(item) 链表尾部添加元素
  • insert(pos, item) 指定位置添加元素
  • remove(item) 删除单链表中与item相等的第一个节点(和列表中的remove操作相似)
  • search(item) 查找节点是否存在

先定义一个节点的类对象:

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

现在可以开始写单链表类了:

class SingleLinkedList():
    #定义一个单向链表的类对象
    #先定义一个head!!!

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

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

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

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

    def add(self, item):
        #头插法:在链表头部添加元素
        node = Node(item)                  #引入要插入的新节点
        node.next = self.__head            #先把新节点的next指向原来的头节点(必须)
        self.__head = node                 #再使self.__head指向新插入的节点(注意和上一步的顺序)

    def append(self, item):
        #尾插法:在链表尾部添加元素
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            # while cur != None:
            #     cur = cur.next
            # cur = node
            while cur.next != None:
                cur = cur.next
            cur.next = node
    
    def insert(self, pos, item):
        node = Node(item)                   #先引入要添加的外部定义好的节点
        if pos <= 0:                        #考虑特殊情况
            self.add(item)
        elif pos >= self.length():
            self.append(item)
        else:  
            pre_cur = self.__head           #定义一个游标,先停留在头节点位置
            count = 0                       #定义计数器
            while count < (pos - 1):        #确定循环条件,因为要插入值是在定义的位置前面,所以要-1且不能有等号
                count += 1
                pre_cur = pre_cur.next      #移动游标到要插入的位置
            node.next = pre_cur.next        #跟头插法一样先操作新插节点的next,使其指向下一个节点
            pre_cur.next = node             #再把插入位置的上一个节点的next指到新插节点头部
    
    def remove(self, item): 
        #删除从头节点开始的第一个相同的节点
        cur = self.__head                   #首先定义一个游标指向头节点
        pre_cur = None                      #再定义一个位于cur前一位的pre_cur游标,此时cur指向头节点因此pre_cur是None
        while cur != None:                  #当cur为None时说明要么这是空链表要么循环已经到链表末端了
            if cur.item == item:            #判断cur当前所指的item是否和要删除的item相同
                if pre_cur == None:         #考虑特殊情况,如果pre游标为None说明cur指向的是第一个节点
                    self.__head = cur.next  #那就另self.__head直接指向cur.next
                else:
                    pre_cur.next = cur.next #否则另此时非空的pre_cur.next指向cur.next
                break
            else:
                pre_cur = cur               #游标逐个后移,注意顺序
                cur = cur.next
        
            
    def search(self, item):                 #这是一个可以优化的search方法
        #查找节点是否存在
        node = Node(item)
        cur = self.__head
        if cur == None:
            return False
        else:
            while cur.item != node.item:
                cur = cur.next
                if cur == None:
                    return False
            return True

开始测试:

if __name__ == "__main__":
    #定义单链表sll
    sll = SingleLinkedList()

    #测试尾插法
    sll.append(0)
    sll.append(1)
    sll.append(2)
    sll.append(3)
    
    #测试insert,注意每插入一个新的元素,后面的元素下标都变了
    sll.insert(0, -0.5)
    sll.insert(1, 555)
    sll.insert(3, 555)
    sll.insert(6, 2.5)

    #测试头插法
    sll.add(-1)
    sll.add(-2)

    #测空
    print("链表sll是否为空?\n" + str(sll.is_empty()) + "\n")

    #测长
    print("链表sll长度?\n" + str(sll.length()) + "\n")

    #遍历打印
    print("遍历链表sll:")
    sll.travel()
    print("\n")

    #测试remove中间节点,结束后打印
    sll.remove(555)
    print("遍历链表sll:")
    sll.travel()
    print("\n")

    #测试remove头节点,并打印
    sll.remove(-2)
    print("遍历链表sll:")
    sll.travel()
    print("\n")

    #测试remove尾节点并打印
    sll.remove(3)
    print("遍历链表sll:")
    sll.travel()
    print("\n")

    #测试remove一个不存在的节点
    sll.remove(123456)
    print("遍历链表sll:")
    sll.travel()
    print("\n")

    #测试search,返回True或False
    print(str(sll.search(555)) + "\n")
    print(str(sll.search(-1)) + "\n")
    print(str(sll.search(123456)) + "\n")

运行一下看看结果是否如期?

链表sll是否为空?
False

链表sll长度?
10

遍历链表sll:
-2 -1 -0.5 555 0 555 1 2 2.5 3

遍历链表sll:
-2 -1 -0.5 0 555 1 2 2.5 3

遍历链表sll:
-1 -0.5 0 555 1 2 2.5 3

遍历链表sll:
-1 -0.5 0 555 1 2 2.5

遍历链表sll:
-1 -0.5 0 555 1 2 2.5

True

True

False

经测试未发现问题,至此单向链表的类对象就初步完成啦。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值