Python实现单向链表的封装

首先我们先了解顺序表和链表的概念,为什么要使用链表。

顺序表和链表

顺序表

顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时需要进行数据搬迁,所以使用起来不是很灵活。
在这里插入图片描述
链表

链表(Linked List) 是一种常见的基础数据结构,是一只种类线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。

链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。

在这里插入图片描述
顺序表和链表的内存分布
在这里插入图片描述

单向链表

单向链表也叫单链表,每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
在这里插入图片描述
表元素域elem 用来存放具体的数据。
链接域next 用来存放下一个节点的位置(python中的标识)
• 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

单链表的操作

在这里插入图片描述
链表实现之前,需要先实现节点,代码如下:

class Node(object):
    """单链表节点的封装"""
    def __init__(self, element):
        self.element = element
        self.next = None

我们先实现判断链表是否为空,链表长度和遍历链表的操作代码:

class Node(object):
    """单链表节点的封装"""
    def __init__(self, element):
        self.element = element
        self.next = None

class SingleLink(object):
    """单链表的封装"""
    def __init__(self):
        # 默认为空
        self._head = None

    def is_empty(self):
        """是否为空"""
        return self._head == None

    def __len__(self):
        """
        求链表长度
            1. 判断是否为空,为空直接返回0
            2. 不为空时依次遍历,长度加1之后将下一个节点赋值给当前
        """
        if self.is_empty():
            return 0
        else:
            cur = self._head
            length = 0
            while cur != None:
                length += 1
                cur = cur.next
            return length

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            print('空链表')
        else:
            cur = self._head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)

单链表的头部添加元素

在这里插入图片描述

class SingleLink(object):
    """单链表的封装"""
    def __init__(self):
        # 默认为空
        self._head = None
        
    def add(self, item):
        """
        头部添加元素:
            1. 创建一个保存item值的节点
            2. 将新节点的next指向头结点,即_head指向的位置
            3. 将链表的头_head指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        node.next = self._head
        self._head = node

指定位置添加元素
在这里插入图片描述

class SingleLink(object):
    """单链表的封装"""
    def __init__(self):
        # 默认为空
        self._head = None
        
    def insert(self, index, item):
        """
        指定位置添加元素
            1. 指定位置为头部之前,则头部添加元素
            2. 指定位置为尾部之后,则尾部添加元素
            3. 中间位置:需要找出指定位置的前一个元素,得到其尾部,插入的节点的尾部指向前面得到的尾部,
                        前一个元素新的尾部指向插入的头部
        :param index:
        :param item:
        :return:
        """

        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 当前节点的位置
            cur = self._head
            # 寻找插入节点的前一个节点
            while count < index - 1:
                count += 1
                cur = cur.next
            # 插入节点的前一个节点的尾部成为了插入节点的尾部指向
            # 然后将插入节点的前一个节点的尾部指向更新为新插入节点的头部
            node.next = cur.next
            cur.next = node

删除节点
在这里插入图片描述

    def remove(self, item):
        """
        删除指定元素的节点
            1. 删除头部节点
            2. 删除其他位置的节点
        :param item:
        :return:
        """
        """
            既然要删除当前节点,首先想的就是遍历链表找到对应节点并且删除,
            这里直接省去了遍历的操作,直接给出了对应的节点。 
            既然想删除当前节点那么将给定的节点的val和next全部转换成当前节点的下一个节点所对应的值,
            那么当前节点在本链表中就相当于替换成了下一个节点。
            """
        cur = self._head
        pre = None
        while cur != None:
            if cur.element == item:
                if not pre:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

尾部添加元素

    def append(self, item):
        """
        尾部添加元素
            1. 先判断链表是否为空,若为空,将_head指向新节点
            2. 若不为空,找到尾部,将尾节点next指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            if cur.next == None:
                cur.next = node

判断元素在链表中是否存在

    def search(self, item):
        """
        判断查找的元素在节点中是否存在,返回Bool类型
        :param item:
        :return:
        """
        cur = self._head
        while cur.next != None:
            if cur.element == item:
                return True
            cur = cur.next
        if cur.element == item:
            return True

        return False

链表与顺序表的对比

操作链表顺序表
访问元素O(n)O(1)
在头部插入/删除O(1)O(n)
在尾部插入/删除O(n)O(1)
在中间插入/删除O(n)O(n)

时间复杂度的不同主要是因为链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找。顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。

python实现单向链表的整体代码

class Node(object):
    """单链表节点的封装"""
    def __init__(self, element):
        self.element = element
        self.next = None

class SingleLink(object):
    """单链表的封装"""
    def __init__(self):
        # 默认为空
        self._head = None

    def is_empty(self):
        """是否为空"""
        return self._head == None

    def __len__(self):
        """
        求链表长度
            1. 判断是否为空,为空直接返回0
            2. 不为空时依次遍历,长度加1之后将下一个节点赋值给当前
        """
        if self.is_empty():
            return 0
        else:
            cur = self._head
            length = 0
            while cur != None:
                length += 1
                cur = cur.next
            return length

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            print('空链表')
        else:
            cur = self._head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)

    def append(self, item):
        """
        尾部添加元素
            1. 先判断链表是否为空,若为空,将_head指向新节点
            2. 若不为空,找到尾部,将尾节点next指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            if cur.next == None:
                cur.next = node


    def add(self, item):
        """
        头部添加元素:
            1. 创建一个保存item值的节点
            2. 将新节点的next指向头结点,即_head指向的位置
            3. 将链表的头_head指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        node.next = self._head
        self._head = node

    def insert(self, index, item):
        """
        指定位置添加元素
            1. 指定位置为头部之前,则头部添加元素
            2. 指定位置为尾部之后,则尾部添加元素
            3. 中间位置:需要找出指定位置的前一个元素,得到其尾部,插入的节点的尾部指向前面得到的尾部,
                        前一个元素新的尾部指向插入的头部
        :param index:
        :param item:
        :return:
        """

        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 当前节点的位置
            cur = self._head
            # 寻找插入节点的前一个节点
            while count < index - 1:
                count += 1
                cur = cur.next
            # 插入节点的前一个节点的尾部成为了插入节点的尾部指向
            # 然后将插入节点的前一个节点的尾部指向更新为新插入节点的头部
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """
        删除指定元素的节点
            1. 删除头部节点
            2. 删除其他位置的节点
        :param item:
        :return:
        """
        """
            既然要删除当前节点,首先想的就是遍历链表找到对应节点并且删除,
            这里直接省去了遍历的操作,直接给出了对应的节点。 
            既然想删除当前节点那么将给定的节点的val和next全部转换成当前节点的下一个节点所对应的值,
            那么当前节点在本链表中就相当于替换成了下一个节点。
            """
        cur = self._head
        pre = None
        while cur != None:
            if cur.element == item:
                if not pre:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next



    def search(self, item):
        """
        判断查找的元素在节点中是否存在,返回Bool类型
        :param item:
        :return:
        """
        cur = self._head
        while cur.next != None:
            if cur.element == item:
                return True
            cur = cur.next
        if cur.element == item:
            return True

        return False

if __name__ == '__main__':
    # 实例化单链表对象
    link = SingleLink()
    # 长度获取
    # print("链表长度:", len(link))
    # # 遍历链表
    # link.travel()
    # print("链表是否为空?", link.is_empty())
    link.add(3)
    print(link.travel())
    link.append(1)
    link.append(2)
    print(link.travel())
    print("链表是否为空?", link.is_empty())
    link.insert(1, 'hello')
    print(link.travel())
    print("链表长度:", len(link))
    link.remove(3)
    print(link.travel())
    print(link.search(2))

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值