数据结构-----线性表(链表)

单向链表

1.定义:将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,每个结点(尾节点除外)中都持有一个指向下一个节点的引用,这样所得到的存储结构为链表结构。

2.特点

  • 逻辑上相邻的元素 ai, ai+1,其存储位置也不一定相邻;
  • 存储稀疏,不必开辟整块存储空间。
  • 对表的插入和删除等运算的效率较高。
  • 逻辑结构复杂,不利于遍历。

"""
linklist.py  链表程序实现
重点代码

思路分析
1. 创建节点类,生成节点对象
包含数据和下一个节点的引用
2. 链表类,生成链表对象
可以对链表进行数据操作
"""

“代码”
class Node():
    """
    一个节点里面包含两个数据,一个是当前的数据,一个是指向下一个数据的next,
    当next数据为None时,次节点为最后一个节点
    """

    def __init__(self, data, next=None):
        self.data = data
        self.next = next


class Linklist():
    def __init__(self):
        "生成一个头节点,头结点为head,假设当前的Node是空值"
        self.head = Node(None)

    # 初始添加一组链表节点
    def linklist(self, list_):
        # 设p为头节点
        p = self.head
        # 循环链表,链表的每一个值都赋值给p.next
        for i in list_:
            p.next = Node(i)
            # 每一次循环 p.next重新赋值为p
            p = p.next

    # 遍历链表
    def shou_link(self):
        # 设p为第一个节点 (链表中头节点和第一个节点是不同的)
        # 如果这里把p设为头节点的话,那while就要从第一节点开始
        p = self.head.next
        # 如果p.next为空值,此时的p.next是链表中的最后一个节点,
        while p is not None:
            # p.data是本次节点的值,循环打印本次的节点的值
            print(p.data, end=" ")
            # 每一次循环 p.next重新赋值为p
            p = p.next
        print()

    # 获取链表的长度
    def get_lenght(self):
        p = self.head
        n = 0
        while p.next is not None:
            n += 1
            p = p.next
        return n

    # 判断链表是否为空
    def empty(self):
        # 如果链表的长度为0,那链表自然是空的
        if self.get_lenght() == 0:
            return True
        else:
            return False

    # 清空链表
    def clear(self):
        # 第一个节点为空值,那就后面的几个节点就断开了,也就相当于清空了
        self.head.next = None

    # 尾部插入节点
    def add_link(self, data):
        # 生成一个新的节点,把这个节点插到尾部
        # node是节点 data是节点的值
        node = Node(data)
        p = self.head
        # 循环出最后一个节点
        while p.next is not None:
            p = p.next
        # 循环完最后一个p为最后一个节点,将最后一个节点用next连接node, node为链表的最后一个节点
        p.next = node

    # 选择位置插入节点
    # 思想:先将新节点的next连接后一个节点,再将前一个节点的next连接新节点
    def insert(self, index, data):
        # 先判断 下标index的位置,要求下标不能小于0和大于链表的长度
        # 如果超出范围,人工报错
        if index < 0 or index > self.get_lenght():
            raise IndexError("index out of range")
        p = self.head
        # 定义p移动到插入位置的前一个
        for i in range(index):  # index从0开始
            # 假如index=0,p=p.next
            # 假如index=1,p=p.next.next
            # 假如index=2,p=p.next.next.next 以此类推
            p = p.next
        node = Node(data)  # 生成一个新的节点
        # 将node插入链表p的后面
        # node的前一个节点p 后一个节点p.next
        node.next = p.next
        p.next = node

    # 删除节点
    # 思想:前一个节点的next 连接到删除节点的后一个节点
    def del_node(self, data):
        p = self.head
        # 查找删除节点的值
        while p.next and p.next.data != data:
            p = p.next
        # 如果循环到最后以为还没找到,说明删除的值不在链表中
        if p.next is None:
            raise ValueError("value is error")
        else:
            #跨过删除的节点,连接删除节点的后面节点
            p.next = p.next.next

    # 通过下标,获取节点的值
    def get_data(self, index):
        if index < 0 or index > self.get_lenght():
            raise IndexError("index out of range")
        # p为第一个节点
        p = self.head.next

        for i in range(index):
            # 同插入节点
            p = p.next
        return p.data


print("-----------测试--------------")
if __name__ == '__main__':
    list = Linklist()
    l = [1, 2, 3, 4, 5]
    list.linklist(l)
    list.shou_link()  # 1 2 3 4 5
    print(list.get_lenght())  # 5
    print(list.empty())  # False
    list.add_link(6)
    list.shou_link()  # 1 2 3 4 5 6
    list.insert(3, 22)
    list.shou_link()  # 1 2 3 22 4 5 6
    list.del_node(5)
    list.shou_link()  # 1 2 3 22 4 6
    print(list.get_data(2))  # 3
    list.clear()

双向链表

  双向链表的介绍

  一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。

  

  上图是双向链表的结构图,即通过上一个节点可以找到下一个,通过下一个也可以找到上一个节点。

双向链表插入和删除的图解

  

  

  

  

代码

# 1、创建节点
class Node(object):
    # 初始化方法
    def __init__(self, item):
        self.item= item
        self.next = None
        self.prev = None

# 2、创建循环链表
class DoubleLinKList(object):
    # 初始化方法
    def __init__(self):
        self._head = None
    
    # 3、判断是否为空
    def is_empty(self):
        """判断链表是否为空"""
        return self._head == None
    
    # 4、求其长度
    def length(self):
        """返回链表的长度"""
        cur = self._head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
    
    # 遍历
    def travel(self):
        """遍历链表"""
        print("你要遍历的链表元素有:",end=" ")
        cur = self._head
        while cur != None:
            print("%s "%cur.item,end=" ")
            cur = cur.next
        print("")
    
    # 5、头插
    def add(self, item):
        """头部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空链表,将_head指向node
            self._head = node
        else:
            # 将node的next指向_head的头节点
            node.next = self._head
            # 将_head的头节点的prev指向node
            self._head.prev = node
            # 将_head 指向node
            self._head = node
    
    # 6、尾插
    def append(self, item):
        """尾部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空链表,将_head指向node
            self._head = node
        else:
            # 移动到链表尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            # 将尾节点cur的next指向node
            cur.next = node
            # 将node的prev指向cur
            node.prev = cur
    
    # 7、查找
    def search(self, item):
        """查找元素是否存在"""
        cur = self._head
        while cur != None:
            if cur.item == item:
                return True
            cur = cur.next
        return False
    
    # 8、指定位置插入
    def insert(self, pos, item):
        """在指定位置添加节点"""
        if pos <= 0 or pos>self.length()+1 :
            print("你输入的位置有误,请重新输入")
        elif pos == 1:
            self.add(item)
        elif pos == self.length()+1:
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 1
            # 移动到指定位置的前一个位置
            while count < (pos - 1):
                count += 1
                cur = cur.next
            # 将node的prev指向cur
            node.prev = cur
            # 将node的next指向cur的下一个节点
            node.next = cur.next
            # 将cur的下一个节点的prev指向node
            cur.next.prev = node
            # 将cur的next指向node
            cur.next = node
    
    # 9、删除
    def remove(self, item):
        """删除元素"""
        if self.is_empty():
            return
        else:
            cur = self._head
            if cur.item == item:
                # 如果首节点的元素即是要删除的元素
                if cur.next == None:
                    # 如果链表只有这一个节点
                    self._head = None
                else:
                    # 将第二个节点的prev设置为None
                    cur.next.prev = None
                    # 将_head指向第二个节点
                    self._head = cur.next
                return
            while cur != None:
                if cur.item == item:
                    # 将cur的前一个节点的next指向cur的后一个节点
                    cur.prev.next = cur.next
                    # 将cur的后一个节点的prev指向cur的前一个节点
                    cur.next.prev = cur.prev
                    break
                cur = cur.next

# 验证
if __name__ == '__main__':
    
    double_link = DoubleLinKList()
    # 头插
    double_link.add(1)
    # 遍历
    double_link.travel()
    # 尾插
    double_link.append(2)
    double_link.travel()
    # 按照索引插入
    double_link.insert(3,4)
    double_link.travel()
    
    double_link.insert(3,3)
    double_link.travel()
    # 删除
    double_link.remove(3)
    double_link.travel()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性表是一种常见的数据结构,它表示具有相同数据类型的一组元素的有序序列。线性表中的元素之间存在一种顺序关系,每个元素都有一个前驱和一个后继(除了第一个元素没有前驱,最后一个元素没有后继)。线性表可以用顺序存储结构或链式存储结构实现。 在顺序存储结构中,线性表的元素按照顺序存储在连续的内存空间中,可以通过元素的下标来访问和操作元素。插入或删除元素时,需要移动其他元素,因此操作的时间复杂度较高。 链式存储结构中,线性表的每个元素都包含一个数据域和一个指针域,指针指向下一个元素。通过指针的链接,元素可以按照任意顺序存储在内存中,插入和删除操作只需要改变指针的指向,因此时间复杂度较低。 线性表常见的操作包括插入、删除、查找、获取长度等。其中插入和删除操作需要注意保持线性表的顺序关系。 常见的线性表有数组、链表、栈和队列。数组是最简单的线性表,通过下标可以直接访问元素;链表是动态存储结构,插入和删除操作方便,但访问元素需要遍历链表;栈是一种特殊的线性表,只允许在表的一端进行插入和删除操作;队列也是一种特殊的线性表,只允许在表的一端进行插入操作,在另一端进行删除操作。这些数据结构在实际应用中都有各自的应用场景和优缺点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值