算法是程序的灵魂,而排序算法 是算法的入门经典,作者在此用python亲自实现了7种主流的排序算法,并做简短的说明.
学习难度:
桶排序 < 冒泡排序 < 选择排序 < 插入排序 < 快速排序 < 归并排序 < 希尔排序
桶排序(简化版)
桶排序:
将列表中最大数与最小数之间的数全部做成标签,贴到N个桶上
将每个元素放到对应值的桶里面(如果有M个相同的元素值,则将M个元素全部放到相应的桶中,取的时候占用M个位置)
最后按照桶编号的先后顺序,从桶中依次取出值,排列完成
__author__ = 'zhaozhao'
def pail_sort(my_list):
max_num = max(my_list)
min_num = min(my_list)
Y_list = list()
for i in range(min_num, max_num+1):
zhao_list = [i, 0]
Y_list.append(zhao_list)
for m in my_list:
for Y in Y_list:
if Y[0] == m:
Y[1] += 1
result = list()
for n in Y_list:
for t in range(0, n[1]):
result.append(n[0])
return result
pass
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("简单桶排序之前的序列:", Y_list)
print("简单桶排序之后的序列:", pail_sort(Y_list))
if __name__ == '__main__':
main()
冒泡排序
冒泡排序:
有N个待排序元素
1.设置游标,游标带领第一个元素开始,与右侧元素(第1个元素)比较,如果大于右侧元素,则二者交换数值,然后游标带领元素继续向右移动,如果小于右侧元素,则不进行交换,游标继续向右移动,当游标移动到列表最右侧,第一轮比较就完成了(共比较N-1次)
2.然后游标回到起始位置,开始第二轮比较,由于最后一个元素已经确定大于剩余的元素所以(第二轮共比较N-2)次。
3.由于每次都只能选取出一个最大值,所以N个元素的数组,进行N-1轮对比即可完成排列
__author__ = 'zhaozhao'
def bubble_sort(my_list):
N = len(my_list)
# 循环的次数
circle_num = N-1
while circle_num > 0:
# 初始的游标值
index_value = 0
while index_value < circle_num:
if my_list[index_value] < my_list[index_value+1]:
pass
else:
my_list[index_value], my_list[index_value+1] = my_list[index_value + 1], my_list[index_value]
# 游标右移一个单位
index_value += 1
pass
circle_num -= 1
print("冒泡排序之后的序列:",my_list)
return my_list
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("冒泡排序之前的序列:",Y_list)
bubble_sort(Y_list)
pass
if __name__ == '__main__':
main()
选择排序
选择排序(升序):
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
__author__ = 'zhaozhao'
def selection_sort(my_list):
# N为列表元素的个数
N = len(my_list)
circle_num = 0
#需要进行N-1次循环
while circle_num < N:
# 每次循环开始的游标索引值 为 circle_num , 结束的索引值为N-1
for m in range(circle_num, N):
if my_list[circle_num] <= my_list[m]:
pass
else:
my_list[circle_num], my_list[m] = my_list[m], my_list[circle_num]
circle_num += 1
print("选择排序之后的序列:",my_list)
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("选择排序之前的序列:",Y_list)
selection_sort(Y_list)
pass
if __name__ == '__main__':
main()
插入排序
插入排序:
序列共有N个元素
将序列分为,已排序序列(第一个元素) 和 未排序序列(除第一个元素以外的其它元素,共N-1个)两部分,然后通过N-1轮循环,将N-1个元素,依次添加到已排序序列中
__author__ = 'zhaozhao'
def insert_sort(my_list):
N = len(my_list)
finish_list = list()
f_len = len(finish_list)
finish_list.append(my_list[0])
# circle_num为待插入的值的索引
for circle_num in range(1, N):
for pre in range(0, circle_num):
# 如果新加入的值比已排序的值小,就把新值加入到 已排序值的前面
if my_list[circle_num] < finish_list[pre]:
finish_list.insert(pre, my_list[circle_num])
break
# 如果新加入的值比已排序的序列最大的值都大,那么
elif my_list[circle_num] >= finish_list[-1]:
finish_list.append(my_list[circle_num])
break
# 如果新加入的值 比已排序的某个值大但比 已排序后面的值小
elif my_list[circle_num] >= finish_list[pre] and my_list[circle_num] < finish_list[pre+1]:
finish_list.insert(pre+1, my_list[circle_num])
break
else:
pass
return finish_list
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("插入排序之前的序列:", Y_list)
insert_sort(Y_list)
print("插入排序之后的序列:", insert_sort(Y_list))
if __name__ == '__main__':
main()
快速排序(面试常用算法)
快速排序
1.选择左侧第一个元素为 基准元素(其实基准元素可以是任意值,这里选择第一个是为了方便叙述)
- 创建两个指针, 左侧指针初始位置在列表首部,右侧指针初始位置在列表尾部
- 先移动(为了保证,两个指针相遇时,所在位置的元素不大于 基准元素)右侧指针(左移),当到达 元素值 小于基准值 的位置停止(等待左侧指针的支援)
- 移动左侧指针(右移),当到达 元素值 大于基准值 的位置停止,将此元素与 右侧指针当时所在位置的值互换.
- 互换元素后,右侧指针继续先移动, 循环 3,4步骤
6, 当左右指针相遇时, 将相遇位置的 元素值与 基准元素对调,完成第一轮循环
7, 此时,基准元素左侧的值都小于 基准值,基准元素右侧的值都大于基准值
8, 递归调用上面的算法,将两侧的 元素列表 进行排序
9, 伴随着层层递归,新的基准值两侧的元素会越来越少,当基准值 无两侧元素时,排序终止
__author__ = 'zhaozhao'
def q_sort(my_list, left, right):
#设置左右指针
left_point = left
right_point = right
stand_num = left
if left > right:
return
while left_point != right_point:
#先移动右指针,如果遇到 比基准值更小 的值,就停下来
while (my_list[right_point] >= my_list[stand_num]) and (left_point < right_point):
right_point -= 1
# 再移动左指针,如果遇到比基准值更大的值,就停下来
while (my_list[left_point] < my_list[stand_num]) and (left_point < right_point):
left_point += 1
# 找到了双方可交换的点后, 开始交换
my_list[left_point], my_list[right_point] = my_list[right_point],my_list[left_point]
# 将基准点 与 指针相遇的点互换
if left_point == right_point:
my_list[stand_num], my_list[left_point] = my_list[left_point], my_list[stand_num]
q_sort(my_list, left, left_point-1)
q_sort(my_list, right_point+1, right)
return (my_list)
def quick_sort(out_of_order):
end = len(out_of_order) - 1
start = 0
q_sort(out_of_order, start, end)
# print("排列完成的数组:",out_of_order)
return out_of_order
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("快速排序之前的序列:", Y_list)
print("快速排序之后的序列:", quick_sort(Y_list))
if __name__ == '__main__':
main()
归并排序(先分后和, 分而治之)
归并排序(python内置sort方法的实现原理):
归并排序是典型的分治法排序,将待排序元素拆成多个分组,分组内部进行排序,然后分组进行合并,最终合并成完整的数组。
__author__ = 'zhaozhao'
# 负责 将列表拆分
def merge_sort(Y_list):
if len(Y_list) <= 1:
return Y_list
# 先将未排序的列表进行分组
num = len(Y_list) // 2
left_list = merge_sort(Y_list[:num])
right_list = merge_sort(Y_list[num:])
# 将分组的列表交给merge函数, merge负责将列表合并
return merge(left_list, right_list)
# 负责将列表合并
def merge(left, right):
left_point = 0
right_point = 0
finish_list = list()
while right_point < len(right) and left_point < len(left):
if left[left_point] <= right[right_point]:
finish_list.append(left[left_point])
left_point += 1
else:
finish_list.append(right[right_point])
right_point += 1
finish_list += left[left_point:]
finish_list += right[right_point:]
return finish_list
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("归并排序之前的序列:", Y_list)
print("归并排序之后的序列:", merge_sort(Y_list))
if __name__ == '__main__':
main()
希尔排序
希尔排序:
希尔排序是为优化插入排序,而创建的算法, 其核心思想是通过设置步长 将元素分组,对每个分组进行快速排序,然后将步长减少,产生新的分组,对每个新分组进行快速排序,当步长减为1时,完成排序
__author__ = 'zhaozhao'
def shell_sort(Y_list):
gap = len(Y_list)
while gap >= 0:
tem_list = list()
if gap == 0:
return Y_list
# 将要抽取的值和索引保存到一个 列表里
for index, value in enumerate(Y_list):
if index % gap == 0:
zhao_list = [index, value]
tem_list.append(zhao_list)
tem_value_list = list()
for i in tem_list:
tem_value_list.append(i[1])
tem_value_list = insert_sort(tem_value_list)
for i, vv in enumerate(tem_value_list):
tem_list[i][1] = vv
# 排序好的值 替换 原位置的值
for iv in tem_list:
Y_list[iv[0]] = iv[1]
gap = gap // 2
return Y_list
def insert_sort(my_list):
N = len(my_list)
finish_list = list()
f_len = len(finish_list)
finish_list.append(my_list[0])
# circle_num为待插入的值的索引
for circle_num in range(1, N):
for pre in range(0, circle_num):
# 如果新加入的值比已排序的值小,就把新值加入到 已排序值的前面
if my_list[circle_num] < finish_list[pre]:
finish_list.insert(pre, my_list[circle_num])
break
# 如果新加入的值比已排序的序列最大的值都大,那么
elif my_list[circle_num] >= finish_list[-1]:
finish_list.append(my_list[circle_num])
break
# 如果新加入的值 比已排序的某个值大但比 已排序后面的值小
elif my_list[circle_num] >= finish_list[pre] and my_list[circle_num] < finish_list[pre+1]:
finish_list.insert(pre+1, my_list[circle_num])
break
else:
pass
return finish_list
def main():
Y_list = [100, 54, 26, 63, 12, 22, 93, 17, 12, 77, 31, 44, 55, 20]
print("希尔排序之前的序列:", Y_list)
print("希尔排序之后的序列:", shell_sort(Y_list))
if __name__ == '__main__':
main()