线性结构----单向链表结构模拟案例

背景

        我们知道: 线性结构有顺序表 和 链表两种存储方式

        顺序表要求: 需要连续的(内存)空间, 如果没有连续的内存空间, 则顺序表扩容就会失败

        针对于这种情况, 我们可以用链表来存储, 它(链表)不需要 连续的空间。 有地儿就行。

概述:

链表属于线性结构, 它是由 节点(Node) 组成的,根据节点的不同, 以及连接方式的不同。

        主要分为:

       1.单向链表:节点由 元素(数值域) 和 接域(地址) 组成,后1个节点的地址为: None

        2.单向循环链表:节点由 元素域(数值域) 和 链接域(地址) 组成,最后1个点的地域为:第1个节点的地址

        3.双向链表:节点由 1个元素域(数值域)和 2个接域(地址域,分别指向当前节点的,后节点地址

组成, 第1个节点的(前)地址域为: None 最后1 个节点的(局)地址域为: None

        4.双向循环链表节点由 1个元素域(数值域) 和 2个链接域(地址域,分别指向当前节点的前,节

点地址) 组成 第1个节点的(前)地址域为: 最后1 个节点的(后)地址最后1 个节点的(局)地址域为: 第1

个节点的地址

需求:

         我们自定义代码, 模拟:(单向)链表 , 每个结点包含两个域:元素域和链接域 . 这个链接指向

链表中的下一个结点 , 而最后一个结点的链接域则指向一个空值None

        ①表元素域item用来存放具体的数据

        ②链接域next用来存放下一个结点的位置

        ③变量head指向链表的头结点(首结点)的位置,从head出发能找到表中的任意结点

分析:

如果采用面向对象的思路来做, 我们需要两个类

        SingleNode类:表示节点类

                属性: item:表示元素域,即: 当前节点存储的数据

                next:表示地址域,即:当前节点的 下1个节点的 地址

         SingleLinkedList类:表示 链表类

                 属性: head属性 表示: 头结点,即:指向链表中的第1个节点,方便我们增,删,改,查...

案例代码如下(含注释):

# 1.定义SingleNode类,表示节点类
class SingleNode:
    # 初始化节点的信息
    def __init__(self,item):
        self.item = item    # 元素域,数值域:存储区具体数据的
        self.next = None    # 链接域,地址域:存储下个节点的地址的

# 2.定义 SingleLinkedList类,表示:(单向)链表
class SingleLinkedList:
    # 2.1初始化链表
    def __init__(self,node=None):
        # head指向 链表中的第一个节点
        self.head = node

    # 2.2 完成功能: is_empty(self)  判断链表是否为空
    def is_empty(self):
        return self.head == None

    # 2.3 完成功能: length(self)   判断链表长度
    def length(self):
        # 1.定义cur(current单词)变量,记录: 当前的节点,初值为:头结点
        cur = self.head
        # 2.定义计数器,记录:节点个数
        count = 0
        # 3.循环实现,判断cur(当前节点) 是否为None,如果不是,就一直循环
        while cur is not None:
            # 4.进到这里,说明是1个非空节点,计数器 + 1
            count += 1
            # 5.判断当前节点后,cur指向下一个节点
            cur = cur.next
        # 6.返回结果
        return count

    # 2.4 完成功能: travel(self.)  遍历整个链表
    def travel(self):
        # 1.定义cur 变量,用于记录:链表中的每一个节点信息,初值:head(头结点)
        cur = self.head
        # 2.判断当前节点是否为空,不为空,就一直循环
        while cur is not None:
            # 3.不为空,就说明有节点信息,一直循环
            print(cur.item)
            # 4.cur指向下一个节点
            cur = cur.next

    # 2.5 完成功能: add(self, item)  链表头部添加元素
    def add(self, item):
        # 1.根据内容(元素值),创建节点
        new_node = SingleNode(item)
        # 2.设置新节点的(地址域)为self.head(之前的节点)
        new_node.next = self.head
        # 3.更新head属性值,因为head是指向(新的)头结点
        self.head = new_node

    # 2.6 完成功能: append(self, item) 链表尾部添加元素
    def append(self, item):
        # 1.根据内容(元素值),创建节点
        new_node = SingleNode(item)
        # 2.判断链表是否为空,为空,就用head直接指向新节点(充当头部节点)
        if self.head == None:
            self.head = new_node
        else:
            # 3.走这里,说明链表不为空,我们就获取链表的最后一个节点
            # 3.1 创建cur变量,指向头部节点
            cur = self.head
            # 3.2 逐个判断,只要当前节点的地址域不为none,就一直获取
            while cur.next is not None:
                cur = cur.next  # 更新当前节点
            # 3.3 走到这里,循环结束,说明获取的节点就是最后一个节点(他的地址域为none)
            # 设置他(最后一个节点)的地址域为 新节点即可
            cur.next = new_node

    # 2.7 完成功能: insert(self, pos, item) 指定位置添加元素
    def insert(self, pos, item):   # pos表示添加的位置
    # 1. 判断添加位置,如果是 小于等于0的,就在首部添加。
        if pos <= 0:
            self.add(item)
    # 2,如果添加位置,大于等于 链表的长度,就在链表尾部添加,
        elif pos >= self.length():
            self.append(item)
    # 3。走这里,说明是在链表的中间添加,正常写逻辑即可。
        else:
            # 4.创建新节点
            new_node = SingleNode(item)
            # 5.创建cur变量,指向: 插入位置前的哪个节点,默认:头结点
            cur = self.head
            # 6.定义count变量,用于计数,获取插入位置前的值
            count = 0
            # 7.判断循环,获取插入位置前的那个元素
            while count < pos - 1:
                cur = cur.next
                count += 1  # 计数器 + 1
            # 走到这里 ,cur记录的就是:插入位置前的那个元素
            # 8.设置新节点的地址域为:当前节点的地址域
            new_node.next = cur.next
            # 9.设置当前节点的地址域为:新的节点
            cur.next = new_node

    # 2.8 完成功能: remove(self, item) 删除节点
    def remove(self, item):
        # 1。定义变量cur,从头结点开始,逐个查找,获取到: 被删除的节点。
        cur = self.head
        # 2。 定义变量pre,表示: 被删除的节点的 前置节点
        pre = None
        # 3。只要Cur不为空,我们就一直遍历,工获取每个节点。
        while cur is not None:
            # 4。判断当前节点的数值域 是否和 要删除的内容(元素值) 相同
            # 4.1 如果相同,说明要被删除,我们还需判断,要删除的节点是否是 头部节点.
            if cur.item == item:
                # 4.1.1 如果是头部节点,直接用 head 指向 cur.next即可
                if cur == self.head:
                    self.head = cur.next
                # 4.1.2 如果不是头部节点,我们用 pre变量来记录 当前节点的地址域(下个节点)
                else:
                    pre.next = cur.next
                break   # return
            else:
                # 4.2 如果不同,说明当前节点不是要被删除的节点,我们继续判断下1个节点.
                pre = cur   # 当前节点(检验过)充当前置节点
                cur = cur.next  # 我们继续判断下一个节点

    # 2.9 完成功能: search(self, item) 查找节点是否存在
    def search(self, item):
        # 1.定义变量cur,记录每一个节点,初值为 : 头部节点
        cur = self.head
        # 2.如果cur节点不为空,我们就一直遍历
        while cur is not None:
            # 3.判断当前节点的item,是否和我们要查找的item值一致
            if cur.item  == item:
                # 走到这里,说明匹配上了
                return True
            # 4.走到这,说明没有匹配上,继续判断下一个节点
            cur = cur.next
        # 5.整个循环结束,走到这,说明没有找到
        return False

# 3.在main中测试
if __name__ == '__main__':
    # 3.1创建单个节点
    sn1 = SingleNode('乔峰')
    print(sn1.item)  # 当前节点的 元素域值
    print(sn1.next)  # 当前节点的 地址域值

    # 3.2创建链表
    linked_list = SingleLinkedList(sn1)
    print(f'目前的头节点是:{linked_list.head}')

    # 3.3 判断链条是否为空
    print('*'*31)
    print(linked_list.is_empty())

    # 3.4 打印链条的长度(元素个数)
    print(f'链条长度为:{linked_list.length()}')

    # 3.5 打印链表内容
    linked_list.travel()

    # 3.6 在链表头部添加
    linked_list.add("虚竹")
    linked_list.add("段誉")

    # 3.7在链表尾部添加
    linked_list.append("直")
    linked_list.append("黄")


    # 3.8 在链表中间添加(插入元素)
    linked_list.insert(2,"真")

    # 3.9 在链表中删除
    linked_list.remove("真")


    # 3.10 在链表中查找
    print(linked_list.search("黄"))


    # 3.15 最后,再次打印链表内容
    linked_list.travel()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值