数据结构--知识点4--链表

一、链表的概念

1、为什么需要链表

  • 顺序表的构建需要预先指导数据大小来申请连续的存储空间,在进行扩充时还需要进行数据的搬迁,所以使用起来不是很方便
  • 链表结构可以充分利用计算机的内存空间,实现灵活的内存动态管理
  • 链表和顺序表都是线性表

2、链表的定义

链表是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每个数据存储单元作为一个节点,并在节点里存放下一个节点的位置信息(即地址),像一条链条一样将每个数据存储单元连接起来,有顺序的存储数据。

数据存储单元(节点):

数据区链接区
存放数据存放下一个数据的地址

二、单向链表

1、单链表的定义

单向链表也叫单链表,是链表中最简单的一种形式,指链表只是单向的。它的每个节点包含两个域,一个信息域(存放数据/元素)一个链接域(存放下一个元素的地址),这个谅解指向链表中的下一个节点,最后一个节点的链接域指向一个空值(用一竖一横标识)

单链表节点:

表元素域下一节点链接域
元素elem下一节点地址next

单链表:
在这里插入图片描述

  • 表元素域用来存放具体的数据
  • 链接域用来存放下一个节点的位置
  • 变量P指向链表的头节点(首节点)的位置,从P出发能找到表中的任意节点

2、python中的变量赋值

比如:
a=10,b=20,如何得到a=20,b=10的结果?
python中:a,b=b,a即可实现
解答:

  1. 在python中变量的赋值不是将数据存放在变量中,而是数据本身有自己的内存,当某个数据被赋值给变量时,变量就指向数据所在的位置,此时数据的地址还是原来的地址,但是变量的指向改变了,如下图
    在这里插入图片描述
  2. 当发生a,b=b,a时,在等号右边,此时b=20,a=10,因此会有a,b=20,10,然后等号左边的变量发生改变,也就是变量的指向发生改变,数据位置不改变,如下图
    在这里插入图片描述

对于单链表中的节点:

在这里插入图片描述
elem=10表示:elem变量指向了存储数据10的地址
next=node2表示:next变量指向node2存储的地址
所以在python中没有特殊的地址变量,而是用等号来连接变量和变量表示的数据,变量等于谁,就将自己指向数据存放的地方

3、单链表在python中的实现

1)节点的操作

# 首先实现节点,elem表示数据、next表示下一节点的链接
class Node(object):
    def __init__(self,elem):
        self.elem=elem
        self.next=None
        

2)单链表的操作

操作描述
is_empty()链表是否为空
length()链表长度
travel()遍历整个链表
add(item)链表头部添加元素
append(item)链表尾部添加元素
insert(pos,item)链表指定位置添加元素
remove(item)删除节点
search(item)查找节点是否存在
# 实现单链表
# 因为单链表的增加元素、查看元素等操作是类实例化后的某个对象的操作,因此使用def定义
class SingleLinkList(object):
    # 定义构造函数,为了初始化对象时将必须用到的属性、方法做一些定义
    def __init__(self,node=None):
        # node=None时表示头节点为空,即P指向的是一个空链表
        # 也可以先创建一个node,然后将创建好的node传进来
        # 又由于self.head属性是只限于类中使用的属性,因此是私有
        # 通过双下划线定义私有属性
        self.__head=node



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

    def length(self):
        """获取链表长度"""
        # 设置一个辅助工具cur,用来移动遍历节点
        # cur刚开始指向head,最后指向None
        cur=self.__head
        # count用来记录数量
        count=0
        # 刚开始为0 表示刚开始指向head,与最后指向None对应
        while(cur != None):
            count += 1
            cur=cur.next  # 游标指向游标的next指向的位置
        return count

    def travel(self):
        """遍历整个链表"""
        cur=self.__head
        while(cur != None):
            # 通过end=' '空一格
            print(cur.elem,end=' ')
            cur=cur.next
        print(' ') # 用来换行

    def add(self,item):
        """链表头部添加元素,头插法"""
        node=Node(item)
        node.next = self.__head
        self.__head=node

    def append(self,item):
        """链表尾部添加元素,尾插法"""
        node=Node(item)
        if self.is_empty():
            self.__head=node
        else:
            cur=self.__head
            while cur.next != None:
                cur=cur.next
            cur.next=node

    def insert(self,pos,item):
        """链表指定位置pos插入元素
        :param pos 从0开始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node=Node(item)
            cur=self.__head
            count=0
            while count < (pos-1):
                count += 1
                cur=cur.next
            node.next=cur.next
            cur.next=node

    def remove(self,item):
        """删除节点,删除遍历找到的第一个符合的值"""
        # cur表示当前节点,pre表示前一个节点
        cur=self.__head
        pre=None
        while cur != None:
            if cur.elem == item:
                # 判断是否是头节点
                if cur == self.__head:
                    self.__head=cur.next
                else:
                    pre.next=cur.next
                break
            else:
                pre=cur
                cur=cur.next


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

结果

此时链表是否为空 True
此时链表长度为: 0
此时链表是否为空 False
此时链表长度为: 1
8 1 2 3 4  
9 8 1 2 3 4  
100 9 8 1 2 3 4  
100 9 8 1 2 3 4 300  
9 8 1 2 3 4 300  

三、双向链表

1、双向链表的定义

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

2、双向链表的操作

  • is_empty() 链表是否为空
  • length() 链表长度
  • travel() 遍历链表
  • add(item) 链表头部添加
  • append(item) 链表尾部添加
  • insert(pos,item) 指定位置插入元素
  • remove(item) 删除节点
  • search(item) 查找节点是否存在

3、python中实现双向链表操作

# 定义节点
class Node(object):
    """节点,有前端节点,后端节点"""
    def __init__(self,item):
        self.elem=item
        self.next=None
        self.prev=None

# 定义双向链表的操作
class DoubleLinkList(object):
    def __init__(self,node=None):
        self.__head=node

    def is_empty(self):
        # 判断时也可以用is,is判断(id,type,value)是否相同,=判断(type,value)是否相同
        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.elem,end=' ')
            cur=cur.next
        print(' ') # 用来换行

    def add(self,item):
        # 头部插入元素
        # 添加元素时,先将新的节点指向连接,再改变旧的
        node=Node(item)
        # self.__head 表示头部指向的节点
        node.next=self.__head
        self.__head=node
        node.next.prev=node

    def append(self,item):
        # 尾部插入节点
        node=Node(item)
        if self.is_empty():
            self.__head=node
        else:
            cur=self.__head
            while cur.next != None:
                cur=cur.next
            cur.next=node
            node.prev=cur
    def insert(self,pos,item):
        # 再指定位置添加元素,在创建连接时,要看之前是否已经改变连接,根据实时的连接来定义新的连接
        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
            node=Node(item)
            # 先建立从新节点出发的连接
            # 并根据实时的连接来定义新的连接
            node.next=cur
            node.prev=cur.pre
            cur.pre.next=node
            cur.pre=node

    def remove(self,item):
        # 删除节点
        cur=self.__head
        while cur != None:
            if cur.elem == item:
                # 先判断是否是首节点
                if cur==self.__head:
                    self.__head=cur.next
                    if cur.next:
                        # 判断下一个节点是否为空,即当前链表是否只有一个节点
                        cur.next.prev=None
                else:
                    # 不是首节点时
                    cur.prev.next=cur.next
                    if cur.next:
                        # 判断下个节点是否为空
                        cur.next.prev=cur.prev
                break
            else:
                cur=cur.next

    def search(self,item):
        # 查找元素是否在链表中
        cur=self.__head
        while cur != None:
            if cur.elem==item:
                return True
            else:
                cur=cur.next
        return False

测试:

if __name__ == '__main__':
    dobllink=DoubleLinkList()
    print('此时链表是否为空', dobllink.is_empty())
    print('此时链表长度为:', dobllink.length())

    dobllink.append(1)
    print('此时链表是否为空', dobllink.is_empty())
    print('此时链表长度为:', dobllink.length())

    dobllink.append(2)
    dobllink.add(8)
    dobllink.append(3)
    dobllink.append(4)
    dobllink.travel()
    dobllink.insert(-1, 9)
    dobllink.travel()
    dobllink.insert(-1, 100)
    dobllink.travel()
    dobllink.insert(10, 100)
    dobllink.travel()
    dobllink.remove(100)
    dobllink.travel()

结果:

此时链表是否为空 True
此时链表长度为: 0
此时链表是否为空 False
此时链表长度为: 1
8 1 2 3 4  
9 8 1 2 3 4  
100 9 8 1 2 3 4  
100 9 8 1 2 3 4 100  
9 8 1 2 3 4 100  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值