Python5-线性表之顺序表和链表

记录python学习,直到学会基本的爬虫,使用python搭建接口自动化测试就算学会了,在进阶webui自动化,app自动化


线性数据结构

线性表

线性表在不同的编程语言和应用场景中有不同的实现和特性,但它们的核心概念是数据元素之间存在线性关系,即每个元素(除了第一个和最后一个)都有一个前驱和一个后继。
性表是一种数据结构,其中数据元素之间存在一对一的线性关系。这意味着除了第一个和最后一个元素外,每个元素都有一个前驱和一个后继。线性表可以是空的,也可以包含任意数量的元素。线性表的特点是:

元素之间存在线性关系,即一对一的关系。
可以是同质的(所有元素类型相同)或异质的(元素类型不同)。

顺序表

顺序表是一种使用连续存储单元依次存储数据元素的线性表。在顺序表中,数据元素在物理位置上是连续的,通常使用数组来实现。顺序表的特点包括:

元素在内存中连续存储。
可以通过计算得到任意位置元素的存储地址(例如,通过索引)。
插入和删除操作可能需要移动元素,这可能导致效率较低。

链表

链表是一种线性表,其中数据元素在内存中不必连续存储,而是通过指针(或引用)相互链接。每个元素包含数据部分和至少一个指针指向序列中的下一个元素。链表的特点包括:

元素在内存中可以是不连续的。
每个节点包含数据和指向下一个节点的指针。
插入和删除操作不需要移动元素,只需要改变指针,因此某些操作可能更高效。
链表可以是单向的(每个节点指向下一个节点)或双向的(每个节点指向前一个和后一个节点)。

链表还是很熟悉啊,单链表和双链表,头插法和尾插法,虽然很少用到,这个可能在后端中都需要熟悉业务以及设计模式才可能用到的。支持离队、插队、也可以使用索引。

常见的线性表数据结构有哪些呢?

虽然咱很少用到,但是也可能会用到,所谓线性:可加性、齐次性、有顺序的即可
数组(Array):数组是最基本的线性表形式,它由相同类型的元素组成,这些元素在内存中连续存储。
示例:一个整数数组 int[] numbers = {1, 2, 3, 4, 5}。
链表(Linked List):链表由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。
示例:一个单链表,每个节点包含一个整数和一个指向下一个节点的引用。
栈(Stack):栈是一种后进先出(LIFO)的数据结构,只能在一端(栈顶)进行添加和删除操作。
示例:一个用于存储临时变量的栈,每次函数调用时,变量被压入栈顶,函数返回时弹出。
队列(Queue):队列是一种先进先出(FIFO)的数据结构,数据从一端进入(队尾),从另一端离开(队首)。
示例:一个用于任务调度的队列,任务按顺序加入队尾,按顺序从队首取出。
双端队列(Deque):双端队列允许从两端进行插入和删除操作。
示例:一个用于缓存最近访问项目的双端队列,可以快速从两端添加或移除项目。
字符串(String):字符串可以看作是字符的线性序列,每个字符占据一个位置。
示例:一个字符串 “hello”,它由五个字符组成,每个字符都是线性排列的。
动态数组(Dynamic Array):动态数组是一种可以动态扩展和收缩的数组,常见的实现有ArrayList(Java)和vector(C++)。
示例:一个动态数组 ArrayList list = new ArrayList<>();,可以动态添加和删除整数。
向量(Vector):向量是动态数组的一种实现,它提供了动态内存分配和数组操作的功能。
示例:一个向量 std::vector vec;,用于存储整数,并可以动态地增加和删除元素。

线性表之顺序表、链表

顺序表示例
# 顺序表(使用Python列表)
# 顺序表增删改查示例

# 增加操作
def insert_sequence_list(seq_list, index, value):
    seq_list.insert(index, value)

# 删除操作
def delete_sequence_list(seq_list, index):
    seq_list.pop(index)

# 修改操作
def update_sequence_list(seq_list, index, value):
    seq_list[index] = value

# 查询操作
def search_sequence_list(seq_list, value):
    return [index for index, elem in enumerate(seq_list) if elem == value]
#这里运用了列表推导式且搭配enumerate格式同时返回序列和对应的索引,注意该参数返回的元组
# 解析:
'''
eq_list:这是一个序列(比如列表、元组等),我们要在这个序列中搜索特定的元素。
enumerate(seq_list):这个函数会遍历seq_list中的每个元素,并返回一个包含元素索引和元素值的元组。例如,如果seq_list是[1, 2, 3],那么enumerate(seq_list)会生成[(0, 1), (1, 2), (2, 3)]。
index, elem in enumerate(seq_list):这里index是元素的索引,elem是元素的值。对于seq_list中的每个元素,enumerate都会产生一对索引和值。
if elem == value:这是一个条件语句,只有当elem(即seq_list中的元素)等于value时,才会执行列表推导式中的表达式。
return [index for index, elem in enumerate(seq_list) if elem == value]:整个表达式的意思是,返回一个包含所有满足elem == value条件的元素的索引的列表。
'''
# 示例
seq_list = [1, 2, 3, 4, 5]
insert_sequence_list(seq_list, 2, 10)  # 在索引2的位置插入10
print(seq_list)  # 输出: [1, 2, 10, 3, 4, 5]

delete_sequence_list(seq_list, 2)  # 删除索引2的元素
print(seq_list)  # 输出: [1, 2, 3, 4, 5]

update_sequence_list(seq_list, 1, 20)  # 将索引1的元素修改为20
print(seq_list)  # 输出: [1, 20, 3, 4, 5]

search_results = search_sequence_list(seq_list, 4)  # 查询值为4的元素索引
print(search_results)  # 输出: [3]

顺序表回显:

[1, 2, 10, 3, 4, 5]  在索引2的位置插入10
[1, 2, 3, 4, 5]  删除索引2的元素
[1, 20, 3, 4, 5]  将索引1的元素修改为20
[3]  查询值为4的元素索引
链表示例
# 链表(自定义链表节点类)
# 链表节点类
class ListNode:
    def __init__(self, value=0, next=None):
        self.value = value
        self.next = next

# 链表类
class LinkedList:
    def __init__(self):
        self.head = None

    # 增加操作
    def insert(self, value):
        new_node = ListNode(value)
        new_node.next = self.head
        self.head = new_node

    # 删除操作
    def delete(self, value):
        current = self.head
        previous = None
        while current and current.value != value:
            previous = current
            current = current.next
        if current:
            if previous:
                previous.next = current.next
            else:
                self.head = current.next

    # 修改操作
    def update(self, old_value, new_value):
        current = self.head
        while current and current.value != old_value:
            current = current.next
        if current:
            current.value = new_value

    # 查询操作
    def search(self, value):
        current = self.head
        index = 0
        while current:
            if current.value == value:
                return index
            current = current.next
            index += 1
        return -1

# 示例
linked_list = LinkedList()
for i in range(1, 6):
    linked_list.insert(i)

linked_list.insert(10)  # 在链表头部插入10
current = linked_list.head
while current:
    print(current.value, end=" -> ")
    current = current.next
print("None")

linked_list.delete(3)  # 删除值为3的节点
current = linked_list.head
while current:
    print(current.value, end=" -> ")
    current = current.next
print("None")

linked_list.update(5, 20)  # 将值为5的节点修改为20
current = linked_list.head
while current:
    print(current.value, end=" -> ")
    current = current.next
print("None")

search_result = linked_list.search(20)  # 查询值为20的元素索引
print(f"Value 20 found at index: {search_result}")

链表回显如下:

10 -> 5 -> 4 -> 3 -> 2 -> 1 -> None  在链表头部插入10
10 -> 5 -> 4 -> 2 -> 1 -> None  删除值为3的节点
10 -> 20 -> 4 -> 2 -> 1 -> None  将值为5的节点修改为20
Value 20 found at index: 1  查询值为20的元素索引

这个代码实现其实理解不难,用的是单链表中头插法

这里我们就以链表插入为例分析下代码作用
class ListNode:
定义了一个名为ListNode的类,用于表示链表中的节点。

def __init__(self, value=0, next=None):
这是ListNode类的构造函数,用于创建一个新的节点实例。它接受两个参数:value(节点存储的值,默认为0)和next(指向下一个节点的引用,默认为None)。

self.value = value
将传入的value参数赋值给当前节点的value属性。

self.next = next
将传入的next参数赋值给当前节点的next属性。

class LinkedList:
定义了一个名为LinkedList的类,用于表示整个链表。

def __init__(self):
这是LinkedList类的构造函数,用于创建一个新的链表实例。

self.head = None
将链表的头节点head初始化为None,表示链表为空。

def insert(self, value):
定义了一个名为insert的方法,用于在链表的头部插入一个新的节点。

new_node = ListNode(value)
创建一个新的ListNode实例,其值为传入的value参数。

new_node.next = self.head
将新节点的next属性设置为当前链表的头节点self.head。

self.head = new_node
将链表的头节点self.head更新为新节点new_node,这样新节点就成为了链表的第一个节点。

接下来是函数调用代码:

linked_list = LinkedList()
创建一个LinkedList实例,并将其赋值给变量linked_list。

for i in range(1, 6):
使用for循环,从15(不包括6)迭代。

linked_list.insert(i)
在每次迭代中,调用insert方法将当前的i值插入到链表头部。

linked_list.insert(10)  # 在链表头部插入10
在循环结束后,再次调用insert方法,将值10插入到链表头部。

current = linked_list.head
将链表的头节点赋值给变量current,用于遍历链表。

while current:
使用while循环,只要current不是None(即链表不为空),就继续循环。

print(current.value, end=" -> ")
打印当前节点的值,并使用end=" -> "参数使得打印的节点值之间用箭头连接,而不是换行。

current = current.next
将current更新为下一个节点,以便在下一次迭代中处理。

print("None")
当current变为None时,表示链表已经遍历完毕,打印"None"表示链表的结束。

回顾下什么是头插法?

链表头插法是一种在链表头部添加新节点的方法。在链表中,头插法特别适用于需要频繁在列表前端插入数据的场景,因为它可以快速地将新元素插入到链表的头部,而不需要遍历整个链表来找到插入点。

头插法的基本步骤:
创建新节点:首先,你需要创建一个新的节点,这个节点将包含你想要添加到链表中的值。

设置新节点的下一个指针:新节点的 next 指针应该指向当前链表的头节点。

更新头节点:将链表的头节点更新为新创建的节点。

头插法的优点:
速度快:头插法的插入操作非常快,因为它不需要遍历链表,只需要常数时间(O(1))。
简单:头插法的逻辑简单,易于实现。
头插法的缺点:
内存消耗:频繁的头插法操作会导致链表的头部分内存消耗增加,因为每次插入都会在链表的头部创建新的节点。
可能的空间浪费:如果链表经常进行头插法和删除操作,可能会造成大量的内存分配和释放,这在某些情况下可能会导致空间浪费。
头插法的Python实现示例:

python
class ListNode:
    def __init__(self, value=0, next=None):
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self):
        self.head = None

    def insert_at_head(self, value):
        new_node = ListNode(value)
        new_node.next = self.head
        self.head = new_node

使用示例

linked_list = LinkedList()
linked_list.insert_at_head(10)
linked_list.insert_at_head(20)
linked_list.insert_at_head(30)

打印链表

current = linked_list.head
while current:
    print(current.value, end=" -> ")
    current = current.next
print("None")

在这个示例中,我们定义了一个 ListNode 类和一个 LinkedList 类。LinkedList 类包含一个 insert_at_head 方法,该方法实现了头插法。每次调用 insert_at_head 方法时,都会在链表的头部插入一个新的节点。最后,我们通过一个循环打印出链表中的所有值,可以看到新插入的节点(30)现在是链表的头节点。
在这里插入图片描述
该说不说,这可能需要一点点计算机专业背景,还好小编以前学过,理解起来比较轻松,实际中若接触都后端算法可能就会用到具体的数据结构,还要根据实际场景需求设计数据结构和数据模型,这可不是一件简单的事情噢,加油,慢慢来,学它个几个月直接投入实践使用,也就那样,该说不说

实践是检验真理的唯一标准

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值