python数据结构及算法
一. 数据结构与算法
1. 算法的概念:算法是独立存在的一种解决问题的方法和思想
2. 算法的特征:输入,输出,有穷性,确定性,可行性
3. 时间复杂度是实现算法程序所需要的时间,即算法的优劣
4. 数据结构是指数据对象中数据元素之间的关系
5. 程序 = 数据结构 + 算法
6. 算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体
二. 顺序表
1. 顺序表:将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示
2. 元素的物理地址 = 首地址 + 元素下标 * 存储单元大小
3. 顺序表分为一体式结构和分离式结构
4. 元素存储区替换:一体式结构需要移动整个数据区;分离式结构只需要移动数据区域链接地址即可
三. 链表
1. 将元素存放在通过链接构造起来的一系列存储块中,在每个结点存放下一个结点的地址
2. 单链表:单链表包含两个域,一个信息域,一个链接域(指向下一个节点)
3. 信息域存放具体的数据,链接域存放下一个结点的地址
4. 单链表操作:
操作 功能 is_empty 链表是否为空 length() 链表长度 travel() 遍历整个链表 add(item) 链表头部添加元素 qppend(item) 链表尾部添加元素 insert(位置,item) 指定位置添加元素 remove(item) 删除节点 search()item *查找节点是否存在
5. 单向循环链表:在单链表的尾部增加了一个指向头结点的链接
6. 双向链表:每个节点都包括一个数据域和两个链接域(一个指向前驱节点,一个指向后继节点)
四. 栈
1. 特点:只允许在容器的一端进行加入数据和输出数据(后进先出)
2. 栈的操作:
操作 功能 stack() 创建一个新的空栈 push(item )添加一个新的元素item到栈顶 pop() 弹出栈顶元素 peek() 返回栈顶元素 is_empty 判断栈是否为空 size() 返回栈的元素个数
五. 队列
1. 队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表(先进先出)
2. 双端队列:可以在任意一端入队和出队
3. 队列操作:
操作 功能 Deque() 创建一个空的双端队列 add_from(item) 在队头加入一个item元素 add_rear(item) 在队尾加入一个item元素 remove_rear() 在队尾删除一个item元素 is_empty 判断双端队列是否为空 size() 返回队列大小
六. 排序与搜索
排序算法是一种能将一串数字依照特定的顺序排列的一种算法
1. 冒泡排序
方法:把数组从前往后,两两比较,较大的数放在最后一位;每轮得到一个最大值且不参与下一轮排序,直到所有数字排序完毕
稳定性:稳定
代码如下:
def bubble_sort ( alist) :
"""冒泡排序"""
n = len ( alist)
for j in range ( n- 1 ) :
count = 0
for i in range ( 0 , n- 1 ) :
"""序列从头走到尾"""
if alist[ i] > alist[ i+ 1 ] :
alist[ i] , alist[ i+ 1 ] = alist[ i+ 1 ] , alist[ i]
count += 1
if 0 == count:
return
2. 选择排序
方法:每一轮找出一个最小值与第一个数交换,第二轮在除了第一个数外其余数里找一个最小的与第二个数交换,依此类推
稳定性:不稳定
代码如下:
def select_sort ( alist) :
"""选择排序"""
n = len ( alist)
for j in range ( n- 1 ) :
min_index = j
for i in range ( j, n) :
if alist[ min_index] > alist[ i] :
min_index = i
alist[ j] , alist[ min_index] = alist[ min_index] , alist[ j]
3. 插入排序
方法:第一轮在前两个数种寻找最小值插入到第一个数,第二轮从前三个数里找最小值插入到第一个数,依此类推
稳定性:稳定
代码如下:
def insert_sort ( alist) :
"""插入排序"""
n = len ( alist)
for j in range ( 1 , n) :
i = j
while i > 0 :
if alist[ i] < alist[ i- 1 ] :
alist[ i] , alist[ i- 1 ] = alist[ i- 1 ] , alist[ i]
i -= 1
else :
break
4. 快速排序
方法:首先,把第一个数设置为基数,使用high和low下标,low在头(但不指向基数),high在尾,向中间移动,移动规则为low向后移动,遇到比基数大的停止,high遇到比基数小的停止,当high和low都停止时,二者交换,继续往中间移动,直到二者重合,把基数插入到重合点前;第二轮把数列以基数为中心分为两部分,继续进行相同操作
稳定性:不稳定
代码如下:
def quick_sort ( alist, first, last) :
"""快速排序"""
if first >= last:
return
mid_value = alist[ first]
low = first
high = last
while low < high:
while low < high and alist[ high] >= mid_value:
high -= 1
alist[ low] = alist[ high]
while low < high and alist[ low] < mid_value:
low += 1
alist[ high] = alist[ low]
alist[ low] = mid_value
quick_sort( alist, first, low- 1 )
quick_sort( alist, low+ 1 , last)
5. 希尔排序
方法:第一轮将数列分为以n//2为一组,每部分的对应位置进行插入排序;第二轮分为n//2//2部分,继续进行相同操作,直到分成n部分
稳定性:不稳定
代码如下:
def shell_sort ( alist) :
"""希尔排序"""
n = len ( alist)
gap = n// 2
while gap > 0 :
for j in range ( gap, n) :
i= j
while i> 0 :
if alist[ i] < alist[ i- gap] :
alist[ i] , alist[ i- gap] = alist[ i- gap] , alist[ i]
i -= gap
else :
break
gap //= 2
6. 归并排序
方法:把数组先分为n/2为一组,再分为n/2/2为一组,直到n/n为一组,再把数字两两合并,第一次合并时,合并成2个为一组,根据左下标和右下标比较,较小的数先输出,直到一组数据为空,另一组数直接插入,第二次合并时,合并成4个为一组,直到一组数为空
稳定性:稳定
代码如下:
def merge_sort ( alist) :
"""归并排序"""
n = len ( alist)
if n<= 1 :
return alist
mid= n// 2
left_li= merge_sort( alist[ : mid] )
right_li= merge_sort( alist[ mid: ] )
left_pointer, right_pointer= 0 , 0
result= [ ]
while left_pointer < len ( left_li) and right_pointer < len ( right_li) :
if left_li[ left_pointer] < right_li[ right_pointer] :
result. append( left_li[ left_pointer] )
left_pointer+= 1
else :
result. append( right_li[ right_pointer] )
right_pointer+= 1
result+= left_li[ left_pointer: ]
result+= right_li[ right_pointer: ]
return result
7. 搜索
二分查找也叫折半查找,只能作用到顺序表
特点:比较次数少,速度快
七. 树与树算法
度:一个节点含有的子树的个数
树的度:最大的节点含有的子树的个数
节点的层次:从根开始定义,根为第一层,跟的子节点为第二层,依此类推
有序树分为:二叉树,霍夫曼树,B树
1. 二叉树
分类:二叉树分为完全二叉树,满二叉树,平衡二叉树(子树层次相差不大于1),排序二叉树(左小右大)
性质:在二叉树的第i层上至多有2^(i-1)个节点;
深度为k的二叉树至多有2^k-1个节点;
对于任意一颗二叉树,如果其叶子节点数为NO,而度数为2的节点总数为N2,则NO=N2+1;
具有n个节点的完全二叉树的深度为log2(n+1)
2. 树的遍历
分类:先序遍历;中序遍历;后序遍历
先序遍历先遍历根节点,再遍历左子树,再遍历右子树
中序遍历先遍历左子树,再遍历根节点,再遍历右子树
后序遍历先遍历左子树,再遍历右子树,再遍历根节点