一、介绍
1.什么是数据结构
数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。简单来说,数据结构就是设计数据以何种方式组织并存储计算机中。比如:列表、集合、字典都是一种数据结构。即程序=数据结构+算法
2.数据结构的分类
数据结构按照其逻辑结构可以分为线性结构、树结构、图结构。
线性结构:数据结构中的 元素存在一对一的相互关系。
树结构:数据结构中的元素存在一对多的相互关系。
图结构:数据结构中的元素存在多对多的相互关系。
二、栈
1.什么是栈?
栈是一个数据结合,可以理解为只能在一端进行插入或者删除操作的列表。
2.特点:后进先出
3.基本操作:
进栈(压栈):push
出栈:pop
取栈顶:gettoop
4.栈的python实现
不需要自己定义,使用列表结构即可。
进栈函数:append
出栈函数:pop
查看栈顶函数:li[-1]
5.栈的应用(括号匹配问题)
括号匹配问题:给一个字符串,其中白蛤小括号、中括号、大括号、求该字符串中的括号是否匹配。
例如:
()()[]{} 匹配
([{()}]) 匹配
[]( 不匹配
[(]) 不匹配
括号匹配问题实现
def check_kuohao(s): stack=[] for char in s: if char in{'(','[','{'}: stack.append(char) elif char==')': if len(stack)>0 and stack[-1]=='(': stack.pop() else: return False elif char==']': if len(stack)>0 and stack[-1]=='[': stack.pop() else: return False elif char=='}': if len(stack)>0 and stack[-1]=='{': stack.pop() else: return False if len(stack)==0: return True else: return False
迷宫问题(栈实现)

from collections import deque maze = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1] ] dirs = [ lambda x,y:(x-1,y), #上 lambda x,y:(x,y+1), #右 lambda x,y:(x+1,y), #下 lambda x,y:(x,y-1), #左 ] def solve_maze(x1, y1, x2, y2): stack = [] stack.append((x1,y1)) maze[x1][y1] = 2 while len(stack) > 0: # 当栈不空循环 cur_node = stack[-1] if cur_node == (x2,y2): #到达终点 for p in stack: print(p) return True for dir in dirs: next_node = dir(*cur_node) if maze[next_node[0]][next_node[1]] == 0: #找到一个能走的方向 stack.append(next_node) maze[next_node[0]][next_node[1]] = 2 # 2表示已经走过的点 break else: #如果一个方向也找不到 stack.pop() else: print("无路可走") return False def solve_maze2(x1,y1,x2,y2): queue = deque() path = [] # 记录出队之后的节点 queue.append((x1,y1,-1)) maze[x1][y1] = 2 while len(queue) > 0: cur_node = queue.popleft() path.append(cur_node) if cur_node[0] == x2 and cur_node[1] == y2: #到终点 real_path = [] x,y,i = path[-1] real_path.append((x,y)) while i >= 0: node = path[i] real_path.append(node[0:2]) i = node[2] real_path.reverse() for p in real_path: print(p) return True for dir in dirs: next_node = dir(cur_node[0], cur_node[1]) if maze[next_node[0]][next_node[1]] == 0: queue.append((next_node[0], next_node[1], len(path)-1)) maze[next_node[0]][next_node[1]] = 2 # 标记为已经走过 else: print("无路可走") return False solve_maze2(1,1,8,8)
三、队列
1.什么是队列?
队列是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除。
进行插入的一端称为队尾,插入动作称为进队或入队。
进行删除的一端称为对头,删除动作称为出队。
队列的性质:先进先出
双向队列:队列的两端都允许进行进队和出队操作。
2.队列的实现
队列能否简单用列表实现?为什么?
初步设想:列表+两个下标指针
创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0。
进队操作:元素写到li[rear]的位置,rear自增1。
出队操作:返回li[front]的元素,front自减1。
队列的实现原理(环形队列)
3.队列的实现原理(环形队列)
环形队列:当队尾指针front == Maxsize + 1时,再前进一个位置就自动到0。
队首指针前进1:front = (front + 1) % MaxSize
队尾指针前进1:rear = (rear + 1) % MaxSize
队空条件:rear == front
队满条件:(rear + 1) % MaxSize == front
4.队列的内置模块
使用方法:from collections import deque
创建队列:queue = deque(li)
进队:append
出队:popleft
双向队列队首进队:appendleft
双向队列队尾进队:pop
四、链表
1.什么是链表?
链表中每一个元素都是一个对象,每个对象称为一个节点。包含数据域的key和指向下一个节点的指针next,通过各个节点之间的相互转换,,
最终串联成一个链表。
节点的定义:
2.建立链表
3.链表节点的插入和删除
插入: p.next = curNode.next curNode.next = p 删除: p = curNode.next curNode.next = curNode.next.next del p
4.双链表
双链表中每个节点有两个指针:一个指向后面节点、一个指向前面节点。 节点定义: class Node(object): def __init__(self, item=None): self.item = item self.next = None self.prior = None
双链表节点的插入和删除
插入: p.next = curNode.next curNode.next.prior = p p.prior = curNode curNode.next = p 删除: p = curNode.next curNode.next = p.next p.next.prior = curNode del p
链表复杂度分析
列表与链表 按元素值查找 按下标查找 在某元素后插入 删除某元素
五、哈希表
1.什么是哈希表?
哈希表(hash table,又称为散列表),是一种线性表的存储结构。哈希表有一个顺序表(也就是数组)和一个哈希函数组成(哈希函数就是加密算法,顺序表就是加密后的值)。
哈希函数h(k) 将元素k作为自变量,返回元素的存储下标。 简单的哈希函数: 除法哈希:h(k) = k mod m #对m取余 乘法哈希:h(k) = floor(m(kA mod 1)) 0<A<1
假设有一个长度为7的数组,河西函数h(k) = K%7.元素集合{14,22,3,5}的存储方式如下图(制作图片链接https://visualgo.net/en)。
2.哈希冲突
哈希冲突: 由于哈希表的大小是有限的,而要存储的值得总数量是无线的,因此对于任何哈希函数,都会出现两个不同的元素映射到同一个位置上的情况,这种情况就叫做哈希冲突。 解决哈希冲突--开放寻址法: 开放寻址法:如果哈希函数返回的位置已经有值,则可以向后探查新的位置来存储这个值。 线性探查:如果位置i被占用,则探查i+1,i+2····· 二次探查:如果位置i被占用,则探查i+1²,i-1²,i+2²··· 二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时,则尝试使用h3,h3等
拉链法:哈希表每个位置都链接一个链表,当冲突发生时,冲突的元素讲被加到该位置链表的最后(图示略)
3.哈希表在python中的应用
字典与集合都是通过哈希表来实现的 在python中的字典; ls = {"name":"username","password":"password"} 使用哈希表存储字典,通过哈希函数将字典的键映射为下标 在字典键值对数量不多的情况下,几乎不会发生类似于哈希冲突,此时查找一个元素的时间复杂度为O(1)
4.二叉树
二叉树的链式存储:将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来链接。 节点定义: class BiTreeNode(object): def __init__(self,data): self.data = data self.lchild = None #左边的孩纸 self.rchild = None #右边的孩纸 二叉树的遍历方式: 前序遍历: 中序遍历: 后序遍历: 层次遍历:
from collections import deque
class BiTreeNode:
def __init__(self, data):
self.data = data
self.lchild = None
self.rchild = None
a = BiTreeNode('A')
b = BiTreeNode('B')
c = BiTreeNode('C')
d = BiTreeNode('D')
e = BiTreeNode('E')
f = BiTreeNode('F')
g = BiTreeNode('G')
e.lchild = a
e.rchild = g
a.rchild = c
c.lchild = b
c.rchild = d
g.rchild = f
root = e
#前序遍历
def pre_order(root):
if root:
print(root.data, end='')
pre_order(root.lchild)
pre_order(root.rchild)
#中序遍历
def in_order(root):
if root:
in_order(root.lchild)
print(root.data, end='')
in_order(root.rchild)
#后续遍历
def post_order(root):
if root:
post_order(root.lchild)
post_order(root.rchild)
print(root.data, end='')
#层次遍历
def level_order(root):
queue = deque()
queue.append(root)
while len(queue) > 0:
node = queue.popleft()
print(node.data,end='')
if node.lchild:
queue.append(node.lchild)
if node.rchild:
queue.append(node.rchild)
pre_order(root)
print("")
in_order(root)
print("")
post_order(root)
print("")
level_order(root)
遍历完之后比对他们的打印结果你会发现都是不同的
5.二叉搜索树
二叉搜索树是一颗二叉树且满足性质: 设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key<= x.key; 如果y是x右子树的一个节点,那么y.key>=x.key. 二叉搜索树的创建 二叉搜索树的遍历(采用中序序列遍历) 二叉搜索树的查询、插入、删除操作 ps:随机化的二叉搜索树,AVL树
AVL树:avl树是一个自平衡的二叉搜索树。
具有的性质:
根的左右子树的高度之差的绝对值不能超过1
根的左右子树都是平衡二叉树
AV领的实现方式:旋转(在我上边留的网站自己测试,很诡异,了解即可):
B树(B-Tree):B树是一颗自平衡的多路搜索树。常用于数据库的索引。
实例(Bitree树的实现)

from collections import deque class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None a = BiTreeNode('A') b = BiTreeNode('B') c = BiTreeNode('C') d = BiTreeNode('D') e = BiTreeNode('E') f = BiTreeNode('F') g = BiTreeNode('G') e.lchild = a e.rchild = g a.rchild = c c.lchild = b c.rchild = d g.rchild = f root = e def pre_order(root): if root: print(root.data, end='') pre_order(root.lchild) pre_order(root.rchild) def in_order(root): if root: in_order(root.lchild) print(root.data, end='') in_order(root.rchild) def post_order(root): if root: post_order(root.lchild) post_order(root.rchild) print(root.data, end='') def level_order(root): queue = deque() queue.append(root) while len(queue) > 0: node = queue.popleft() print(node.data,end='') if node.lchild: queue.append(node.lchild) if node.rchild: queue.append(node.rchild) pre_order(root) print("") in_order(root) print("") post_order(root) print("") level_order(root)
结果如下: