python动态数组实现_利用python实现动态数组

本文介绍了动态数组的概念,并通过Python实现了一个ArrayList类,包含增、删、改、查等操作。动态数组在内存不足时会自动扩容,删除元素后可以缩容。示例代码展示了如何使用这个ArrayList类进行元素的管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、数组

说动态数组之前,首先要说数组,数组是一种顺序存储的线性表,所有元素的内存地址都是连续的。数组的最大优点是他的查找时间复杂度能够达到O(1),但是增和删的时间复杂度较高O(n)

二、动态数组

动态数组,即根据用户的输入动态扩充或缩小当前数组的容量。在python中,已经内置了动态数组,叫做列表,List

下面是利用python代码实现动态数组的增删改查操作。

# ArrryList.py

class Arr:

# 设置两个常亮,分别是默认容量大小与未找到元素返回的值

DEFAULT_CAPACITY = 10

ELEMENT_NOT_FOUND = -1

# 初始化,若用户未指定数组大小或者小于默认,直接使用默认容量,否则容量为用户指定

def __init__(self, capacity=DEFAULT_CAPACITY):

capacity = self.DEFAULT_CAPACITY if capacity < self.DEFAULT_CAPACITY else capacity

self._capacity = capacity

self._size = 0

self._elements = [None] * self._capacity

def size(self):

return self._size

def is_empty(self):

# return True if self._size == 0 else False

# 改进上面这还代码,因为在python中所有值都可以转布尔,所以利用隐式布尔值

return self._size == 0

# 查看元素是否存在--->bool

def contains(self, element):

# if self.index_of(element):

# return True

# return False

return True if self.index_of(element) else False

# 根据索引添加,添加结束后判断是否需要扩容

def add(self, index, element):

self._out_of_index(index)

self._size = i = self._size + 1

while i >= index:

self._elements[i] = self._elements[i - 1]

i -= 1

self._elements[index] = element

self._expend_capacity()

# 数组末尾追加,添加结束后判断是否需要扩容

def add_last(self, element):

self._out_of_index(self._size)

self._elements[self._size] = element

self._size += 1

self._expend_capacity()

# 根据索引取值

def get(self, index):

self._out_of_index(index)

return self._elements[index]

# 根据索引改值

def set(self, index, element):

self._out_of_index(index)

self._elements[index] = element

# 删除元素,若用户未指定参数,默认删除最后一个元素,删除后判断是否要缩容

def remove(self, index=ELEMENT_NOT_FOUND):

self._out_of_index(index)

if index == self.ELEMENT_NOT_FOUND:

self._remove_last()

# 删除元素后,该索引后的每个元素都要往前移一格,然后数组大小减一

i = index

while i <= self._size:

self._elements[i] = self._elements[i + 1]

i += 1

self._size -= 1

self._reduce_capacity()

# 返回第一个匹配传入值的索引

def index_of(self, element):

for index in range(self._size + 1):

if element == self._elements[index]:

return index

return self.ELEMENT_NOT_FOUND

def clear(self):

self._size = 0

return self._size

# 判断索引是否越界

def _out_of_index(self, index):

if index < 0 or index > self._size + 1:

raise IndexError('index out of range')

# 当容量不够时动态扩容,默认为扩大为原来的1.5倍

def _expend_capacity(self):

# 当size小于容量,直接返回,当size正好等于容量,需要扩容

if self._size < self._capacity - 1:

return

self._capacity = self._capacity * 2

self._new_elements = [None] * self._capacity

for i in range(self._size):

self._new_elements[i] = self._elements[i]

self._elements = self._new_elements

# 动态缩容,默认缩小到当前的一半

def _reduce_capacity(self):

# 当size小于默认容量或者大于当前容量的一半时直接返回

if self._size <= self._capacity or self._size > (self._capacity // 2):

return

self._capacity = (self._capacity // 2).__ceil__()

for i in range(self._size):

self._new_elements[i] = self._elements[i]

self._elements = self._new_elements

def __str__(self):

arrlist = ''

num = 0

for i in self._elements:

if num == self._size:

break

arrlist = arrlist + str(i) + ','

num += 1

arrlist = arrlist.strip(",")

arrlist = '[' + arrlist + ']'

return arrlist

"""

删除最后一个元素,因为最后一个元素也是往前移动一格,虽然size-1,但是其实最后一个元素引用了两次,

即当前的数组末尾加上原来位置的引用,无法回收,所以对于最后一个元素要手动设置为None

"""

def _remove_last(self):

self._size -= 1

self._elements[self._size] = None

self._reduce_capacity()

# 测试文件,test.py

if __name__ == '__main__':

from ArrayList import Arr

a = Arr()

# a = a #type:Arr

a.add_last(11)

a.add_last(22)

a.add_last(33)

a.add_last(44)

a.add_last('55')

a.add_last(66)

a.add_last(77)

a.add_last(88)

a.add_last(99)

# a.add(2,'st')

# a.remove(2)

# print(a.size())

# print(a.is_empty())

# print(a.contains('55'))

# print(a.index_of(99))

# print(a.get(789))

# a.set(-1,99)

# a.clear()

print(a)

<think>好的,用户想知道如何在Python中删除数组中的指定值。首先,我需要回忆相关的知识和方法。根据之前学过的内容,Python中的数组通常指的是列表,或者也可能是numpy数组。不同的数据结构有不同的处理方法,所以得先区分清楚。 用户的问题里提到了“数组”,在Python中列表(list)是最常用的类似数组的结构,而numpy数组则是用于数值计算的高效结构。所以可能需要分别给出两种情况的解决方法。 首先处理普通的Python列表。删除特定值的方法有多种。常见的有循环遍历并删除,或者使用列表推导式。不过需要注意的是,在遍历列表时直接删除元素可能会导致索引错误或者遗漏元素,所以最好避免在遍历过程中修改列表。例如,用户可能尝试用for循环和remove方法,但如果列表中有多个相同的元素,可能会漏掉一些,因为每次删除元素后列表的长度会变化,但循环的索引还在继续增加。这种情况下,使用列表推导式更安全,直接创建一个新列表,排除所有指定值的元素。例如,new_list = [x for x in original_list if x != value]。这种方法简单有效,而且不会修改原列表,而是生成一个新的列表。 但用户可能希望原地修改列表,即直接改变原列表而不是创建新列表。这时候可以使用循环,不过要从后往前遍历,这样删除元素时不会影响未处理的元素。比如,从最后一个元素开始检查,如果等于目标值,就删除。这样前面的元素索引不会因为删除后面的元素而改变,避免错误。 另外,用户提到的引用[4]中提到了双指针法,这在处理原地删除时非常高效,类似于LeetCode上的“移除元素”问题。快指针遍历每个元素,慢指针指向下一个可以存放非目标值的位置。当快指针遇到不等于目标值的元素时,将其复制到慢指针的位置,然后慢指针前移。这样遍历结束后,慢指针的位置就是新数组的长度,前面的元素都是不需要删除的元素。这种方法时间复杂度是O(n),空间复杂度是O(1),非常高效,适用于需要原地修改且空间复杂度要求低的情况。 接下来是numpy数组的处理。numpy库是Python中处理科学计算的核心库,它的数组操作和普通列表不同。用户想要删除特定值的元素,可以使用布尔索引。例如,创建一个布尔掩码,标记不等于目标值的元素,然后用这个掩码来索引原数组,得到新数组。例如,new_array = arr[arr != value]。这种方法简洁高效,但需要注意的是,numpy数组的大小是固定的,不能像列表那样动态改变,因此删除元素实际上是创建了一个新的数组,而不是原地修改。此外,引用[2]中提到了使用np.sum来统计特定值的出现次数,但删除元素的话还是用布尔索引更直接。 用户提供的引用中,引用[3]提到不能在迭代时删除元素,这和之前的思路一致,即避免在遍历时修改列表结构。引用[1]和[4]分别展示了列表推导式和双指针的方法,这些都是正确的解决方案。 需要将不同的方法整理清楚,分点说明,并给出示例代码。同时,针对不同的数据结构(列表和numpy数组)分别说明。还要注意用户可能对原地修改和生成新数组的需求不同,所以需要明确每种方法的特点,比如是否创建新数组,时间复杂度,适用场景等。 最后,生成相关问题,可能需要包括性能比较、不同数据结构的处理、优化方法等。例如,如何高效处理大规模数据,或者如何处理多维数组中的特定值等。 总结回答的结构: 1. 普通列表的几种方法: a. 列表推导式(创建新列表) b. 原地修改(从后向前遍历删除) c. 双指针法(原地修改,高效) 2. numpy数组的方法: a. 布尔索引创建新数组 然后给出示例代码,说明每种方法的实现步骤。并引用相关的引用内容,如引用[4]的双指针法,引用[2]的numpy方法。 需要确保LaTeX格式正确,行内公式用$...$,独立公式用$$...$$,但这个问题可能不涉及数学公式,但如果有的话需要检查。例如,在时间复杂度说明时,可能需要提到$O(n)$,所以用行内公式。 最后,生成相关问题,可能涉及不同方法的比较、应用场景、性能分析等。</think>在Python中删除数组中的指定值可以通过多种方法实现,具体取决于数据类型(普通列表或NumPy数组)和需求(是否原地修改)。以下是详细方法和示例: --- ### **一、普通列表(list)的删除方法** #### **1. 列表推导式(创建新列表)** 通过生成新列表过滤掉指定值,不修改原列表: ```python original_list = [2, 5, 3, 5, 7] value_to_remove = 5 new_list = [x for x in original_list if x != value_to_remove] # 结果:new_list = [2, 3, 7] ``` **特点**:时间复杂度$O(n)$,空间复杂度$O(n)$,适用于不要求原地修改的场景[^1]。 #### **2. 原地修改(反向遍历删除)** 从后向前遍历列表,直接删除指定值: ```python original_list = [2, 5, 3, 5, 7] value_to_remove = 5 for i in range(len(original_list)-1, -1, -1): if original_list[i] == value_to_remove: del original_list[i] # 结果:original_list = [2, 3, 7] ``` **特点**:时间复杂度$O(n)$,空间复杂度$O(1)$,避免索引错位问题[^3]。 #### **3. 双指针法(原地高效修改)** 使用快慢指针实现原地删除,类似LeetCode的[移除元素](https://leetcode.cn/problems/remove-element/)问题[^4]: ```python def remove_element(nums, val): slow = 0 for fast in range(len(nums)): if nums[fast] != val: nums[slow] = nums[fast] slow += 1 return slow # 新数组有效长度为slow original_list = [2, 5, 3, 5, 7] new_length = remove_element(original_list, 5) # 结果:original_list[:new_length] = [2, 3, 7] ``` **特点**:时间复杂度$O(n)$,空间复杂度$O(1)$,无需额外空间。 --- ### **二、NumPy数组的删除方法** #### **布尔索引(创建新数组)** 利用条件筛选生成新数组: ```python import numpy as np arr = np.array([2, 5, 3, 5, 7]) value_to_remove = 5 new_arr = arr[arr != value_to_remove] # 结果:new_arr = [2, 3, 7] ``` **特点**:适用于数值计算场景,生成新数组[^2]。 --- ### **方法对比** | 方法 | 数据类型 | 是否原地修改 | 时间复杂度 | 空间复杂度 | |--------------------|------------|--------------|------------|------------| | 列表推导式 | 普通列表 | 否 | $O(n)$ | $O(n)$ | | 反向遍历删除 | 普通列表 | 是 | $O(n)$ | $O(1)$ | | 双指针法 | 普通列表 | 是 | $O(n)$ | $O(1)$ | | NumPy布尔索引 | NumPy数组 | 否 | $O(n)$ | $O(n)$ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值