数组
概念:是存放在连续内存空间上的相同类型数据的集合
在 Python 中,与传统数组不同,Python 中的数组通常指的是列表(List),它是一种动态的、可变长度的数据结构
需要注意的是其内存空间的地址是连续的,也就是说如果要增删元素的话,也会影响其他元素的地址,且数组是不能删的,只能覆盖。
列表基本操作:
#创建数组:
#使用方括号 [] 来创建一个空列表,或者在方括号中添加元素来初始化列表。
my_list = [] # 创建一个空列表
my_list = [1, 2, 3] # 创建一个包含元素的列表
#访问元素:
#使用索引来访问列表中的元素,索引从0开始,负数索引表示从末尾开始计数。
my_list = [1, 2, 3]
print(my_list[0]) # 输出第一个元素:1
print(my_list[-1]) # 输出最后一个元素:3
#修改元素:
#可以通过索引来修改列表中的元素。
my_list = [1, 2, 3]
my_list[0] = 4 # 将第一个元素修改为4
print(my_list) # 输出:[4, 2, 3]
#添加元素:
#使用 append() 方法在列表末尾添加一个元素,或使用 insert() 方法在指定位置插入元素。
my_list = [1, 2, 3]
my_list.append(4) # 在末尾添加元素4
my_list.insert(1, 5) # 在索引为1的位置插入元素5
print(my_list) # 输出:[1, 5, 2, 3, 4]
#删除元素:
#使用 del 关键字或 remove() 方法删除列表中的元素。
my_list = [1, 2, 3, 4]
del my_list[2] # 删除索引为2的元素
my_list.remove(1) # 删除值为1的元素
print(my_list) # 输出:[2, 4]
#切片操作:
#使用切片操作符 : 来获取列表的子列表。
my_list = [1, 2, 3, 4, 5]
sub_list = my_list[1:4] # 获取索引为1到3的子列表
print(sub_list) # 输出:[2, 3, 4]
在 Python 中,列表(List)提供了一些内置方法和操作符,还可以进行排序、反转和查找操作。下面是这些操作的示例代码:
1. 排序:
使用 `sort()` 方法可以对列表进行排序。默认情况下,它会按照元素的自然顺序进行升序排序。
my_list = [3, 1, 4, 2, 5]
my_list.sort()
print(my_list) # 输出:[1, 2, 3, 4, 5]
如果需要按照其他规则进行排序,可以使用 `key` 参数来指定一个函数,该函数将应用于列表中的每个元素,并根据函数的返回值进行排序。
my_list = ["apple", "banana", "cherry", "date"]
my_list.sort(key=len) # 按照字符串长度进行排序
print(my_list) # 输出:['date', 'apple', 'cherry', 'banana']
2. 反转:
使用 `reverse()` 方法可以将列表中的元素顺序反转。
my_list = [1, 2, 3, 4, 5]
my_list.reverse()
print(my_list) # 输出:[5, 4, 3, 2, 1]
3. 查找:
使用 `index()` 方法可以查找指定元素在列表中的索引位置。如果元素不存在,会抛出 ValueError 异常。
my_list = [1, 2, 3, 4, 5]
index = my_list.index(3)
print(index) # 输出:2
另外,可以使用 `in` 关键字来判断一个元素是否存在于列表中。
my_list = [1, 2, 3, 4, 5]
if 3 in my_list:
print("Element found")
二分查找
前提:1.有序数组 2.元素无重复(如果有重复返回结果不唯一)
概念:将数据分为二等份,再比较键值和中间值的大小,如果键值小于中间值,可确定要查找的数据在前半边,否则反之,一直分割次数或者确定不存在为止。
二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
二分查找涉及的很多的边界条件,逻辑较简单,但就是写好很难。例如到底是 while(left < right)
还是 while(left <= right)
,到底是right = middle
呢,还是要right = middle - 1
呢?
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
代码示例:
import random
def bin_search(data, val):
low = 0
high = 49
while low <= high and val != -1:
mid = int((low + high) / 2)
if val < data[mid]:
print('%d介于位置%d[%3d]和中间值%d[%3d]之间,找左半边' \
% (val, low + 1, data[low], mid + 1, data[mid]))
high = mid - 1
elif val > data[mid]:
print('%d介于中间值位置%d[%3d]和%d[%3d]之间,找右半边' \
% (val, mid + 1, data[mid], high + 1, data[high]))
low = mid + 1
else:
return mid
return -1
data = [0] * 50
val = 1
for i in range(50):
data[i] = val
val = val + random.randint(1, 5)
while True:
val = int(input('请输入查找键值(1-150),输入-1结束: '))
if val == -1:
break
num = bin_search(data, val)
if num == -1:
print('#####没有找到[%3d]' % (val))
else:
print('在第%2d个位置找到[%3d]' % (num + 1, data[num]))
print('数据内容为:')
for i in range(5):
for j in range(10):
print('%3d-%-3d' % (i * 10 + j + 1, data[i * 10 + j]), end='')
print()
链表
概念:链表是一种通过指针串联在一起的线性表,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。(每个节点有两个指针,分别指向前一个节点和后一个节点。)
链表的长度可以根据需要进行动态调整,链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
重要思路:想要访问这个元素就要知道上一个元素(因为存储在上一个指针里了),可以将需要的值进行存储,增删改可能会改变指针。还可以使用虚拟头节点法
在Python中,链表可以通过自定义类来实现。
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# 创建链表节点
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
# 构建链表关系
node1.next = node2
node2.next = node3
单链表中的指针域只能指向节点的下一个节点。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
双链表 既可以向前查询也可以向后查询。
循环链表,顾名思义,就是链表首尾相连。
增删:
(1)删除链表的第一个节点:只需要把链表头指针指向第二个节点即可。
python中的算法为:
top = head
head = head.next
(2)增加一个节点在最后:
(3)删除链表内的中间节点:(也是同理)
只要将删除节点的前一个节点的指针指向将要被删除节点的下一个节点即可。
最后讨论一下数组和链表的使用区别:
链表常增删,不经常查找。
数组常查找,不经常增删。