常用排序查找算法
一、排序算法
基础类排序
直接插入排序
代码实现
def insert_sort(arr):
length = len(arr)
for i in range(1, length):
j = i - 1
temp = arr[i]
while j >= 0 and temp < arr[j]:
arr[j + 1] = arr[j]
j -= 1
else:
arr[j + 1] = temp
return arr
if __name__ = '__main__':
a = [2, 4, 6, 7]
print(insert_sort(a))
希尔排序
技术要点
希尔排序是在直接插入排序的基础上做的改进,也就是将带排序的序列按固定增量分成若干组,等距者在同一组中。然后再在组内进行直接插入排序。这里固定增量从n/2开始,以后每次缩小一半。
代码实现
def shell_sort(arr, length_arr):
dk = int(length_arr / 2)
while dk >= 1:
# 下面这个for循环可以起到为每一个分组执行直接插入排序的作用
# 第一轮:它将每一个分组的第二个数字和每个分组的第一个数组做插入排序
# 第二轮:它将每个分组的第三个数字和前两个数组做插入排序
# 依次类推
for i in range(dk, length_arr):
position = i
index = i
temp = arr[position]
j = int(index / dk)
index = index - j * dk
while position > index and temp < arr[position - dk]:
arr[position] = arr[position - dk]
position = position - dk
else:
arr[position] = temp
dk = int(dk / 2)
return arr
交换类排序
冒泡排序
代码实现
def bubble_sort(arr):
length = len(arr)
for i in range(length - 1):
flag = False
for j in range(length - 1 - i):
if arr[j] > arr[j + 1]:
flag = True
arr[j], arr[j + 1] = arr[j + 1], arr[j]
if not flag:
break
return arr
快速排序
思路
冒泡排序中,在扫描的过程中只比较两个相邻的两个元素,所以在交换两个相邻元素时只能消除一个逆序。其实也可以对两个不相邻的元素进行交换,这样做的好处是能消除待排序记录中的多个逆序,从而加快排序速度。
快速排序的基本思路如下:
1)从待排序记录中选取一条记录,通常选取第一条记录,将其关键字设置为K1。
2)将关键字小于K1的记录移到K1前面,将关键字大于K1的记录移到K1后面,结构记录被分成两个子表
3)将K1插入到其分界线的位置。
通常将上述过程称为一趟快速排序,通过一次划分之后,会以关键字K1的这条记录作为分界线,将待排序序列分成两个子表。可以对分割后的字表继续按照上述的原则进行分割,知道所有子表的长度不超过1未知。
快速排序法基于分治的思想,具体的步骤如下:
1)从数列中挑选出一个元素,将该元素称为基准元素
2)扫描一遍数列,将所有比基准元素小的元素排在基准元素的前面,将所有比基准元素大的元素排在基准元素的后面。
3)使用递归将各子序列划分为更小的序列,直到把小于基准元素的子数列和大于基准元素的子数列排序完。
代码实现
def quick_sort(arr):
if len(arr) == 1 or len(arr) == 0:
return arr
base = arr[0]
base_arr = [item for item in arr if item == base]
low_arr = [item for item in arr if item < base]
high_arr = [item for item in arr if item > base]
return quick_sort(low_arr) + base_arr + quick_sort(high_arr)
选择排序
在选择排序中,每一趟从待排序的记录中选出关键字最小的记录,顺序的放在已排序好的子文件最后,直到排序完全部记录为止。常用的选择排序有两种,分别是直接选择排序和堆排序。
直接选择排序
代码实现
def select_sort(arr):
length = len(arr)
for i in range(length - 1):
smallest = i
for j in range(i + 1, length):
# 找到比当前值小的index,则进行两值交换
if arr[j] < arr[smallest]:
arr[smallest], arr[j] = arr[j], arr[smallest]
return arr
堆排序
思路
堆排序的具体做法是:将所有待排序的记录的关键字存放在数组r[1…n]中,将r用一颗完全二叉树的顺序表示。每个节点表示一条记录,第一条记录r[1]作为二叉树的跟,后面的各条记录r[2…n]依次逐层从左到右顺序排列,任意r[i]的左孩子是r[2i]右孩子是r[2i+1]双亲是r[i/2]。调整这颗完全二叉树,使得各节点关键字的值满足以下条件。
r[i].key >= r[2i].key且r[i].key >= r[2i+1].key (i=1, 2,,,[n/2])
将满足上述条件的完全二叉树称为堆。
堆排序的过程主要需要解决以下几个问题:
1)如何重建堆
2)如何用任意序列建初堆
3)如何用堆进行排序
- 重建堆
重建堆的过程非常简单,只需要以下两个移动步骤即可。
(1)移出完全二叉树跟节点中的记录,该记录称为待调整记录,此时的跟节点接近于空节点。
(2)从空节点的左子,右子中选出一条关键字较小的记录,如果该记录的关键字小于待调整记录的关键字,则将该记录上移至空节点。此时原来那个关键字较小的子节点相当于空节点。
重复以上步骤,直到空节点的左子,右子的关键字均不小于待调整记录的关键字为止,此时将带调整记录放入到空节点即可完成重建。通过以上调整方法,实际上是对待调整记录实现了逐步向下筛选出来,所以上述过程称为“筛选”法。 - 用任意序列初建堆
将任意序列看成完全二叉树,可以利用筛选法,自底层向上逐层把所有子树调整为堆,直到将整个二叉树调整为堆。可以确定最后一个非叶节点位于第[n/2]个元素,n为二叉树节点数目。所以筛选必须冲第n/2个元素开始,逐层向上倒退,直到跟节点为止。 - 利用堆进行排序
(1)将待排序记录按照堆的定义建立一个初堆,并输出堆顶元素,
(2)调整剩余的记录序列,使用筛选法将前n-1个元素重新筛选,以便建成一个新堆,然后输出堆顶元素。
(3)重复执行步骤2,实现n-1此筛选,这样新筛选出来的堆会越来越小。而新堆后面的有序关键字会越来越多,最后是待排序列称为一个有序序列,这个过程称为堆排序。
可以参考一下连接来理解堆排序
https://blog.csdn.net/qq_34840129/article/details/80638225
代码实现
# -*-coding:utf-8-*-
# 调整堆
def adjust_heap(arr, i, size):
left = 2 * i + 1
right = 2 * i + 2
m = i
if i < size / 2:
if left < size and arr[left] > arr[m]:
m = left
if right < size and arr[right] > arr[m]:
m = right
if m != i:
arr[m], arr[i] = arr[i], arr[m]
adjust_heap(arr, m, size)
# 创建堆
def build_heap(arr, size):
for i in range(0, (int(size / 2)))[::-1]:
adjust_heap(arr, i, size)
def heap_sort(arr):
size = len(arr)
build_heap(arr, size)
for i in range(0, size)[::-1]:
arr[0], arr[i] = arr[i], arr[0]
adjust_heap(arr, 0, i)
return arr
if __name__ == '__main__':
a = [9, 4, 5, 2, 3, 1, 11, 19, 12, 15, 18, 20, 22, 30]
print(heap_sort(a))
归并排序
思想
- 自底向上的方法
- 自顶向下的方法
使用自顶向下的方法更加简洁。
假设归并当前的区间是R[low, heigh],分治法的三个步骤如下。
1)分解:将当前区间一分为二,即求分裂点。
2)求解:递归地对两个子区间R[low, mid]和R[mid+1, high]进行归并排序。
3)组合:将已排序的两个区间R[low, mid]和R[mid+1, high]归并为一个有序的区间。
代码实现
# -*-coding:utf-8-*-
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = int(len(arr) / 2)
left = merge_sort(arr[0:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
l = left[0]
r = right[0]
if l <= r:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
if i < len(left):
result.extend(left[i:])
if j < len(right):
result.extend(right[:])
return result
if __name__ == '__main__':
a = [9, 4, 5, 2, 3, 1, 11, 19, 12, 15, 18, 20, 22, 30]
print(merge_sort(a))