排序算法
对一序列对象根据某个关键字进行排序。
常用术语:
- 稳定与不稳定
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面; - 内排序与外排序
内排序:所有排序操作都在内存中完成;
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
排序算法的性能三大影响因素:
- 时间性能(时间复杂度): 一个算法执行所耗费的时间。
- 辅助空间 (空间复杂度):运行完一个程序所需内存的大小。
- 算法的复杂性 : 算法本身的复杂度,而不是指算法的时间复杂度
交换排序(冒泡排序,快速排序)
冒泡排序:冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端。
'''
冒泡排序算法的运作如下:
1. 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。
这步做完后,最后的元素会是最大的数。
3. 针对所有的元素重复以上的步骤,除了最后一个。
4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
'''
def bubbleSort(arr):
n = len(arr)
# 遍历所有数组元素
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
arr = [64, 34, 25, 12, 22, 11, 90]
bubbleSort(arr)
print ("排序后的数组:")
for i in arr:
print ("%d" %(i),end=',')
---------------------------------------------------
排序后的数组:
11,12,22,25,34,64,90,
快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
将‘4’作为第一趟排序的关键字:
arr=[10,5,2,3]
def Quick_sort(arr):
if len(arr)<2:
return arr#基线条件:为空或只包含一个元素的数组是有序的
else:
pivot=arr[0]#递归条件
less=[i for i in arr[1:] if i <= pivot]#由所有小于基准值的元素组成子数组
greater=[i for i in arr[1:] if i> pivot]#由所有大于基准值的元素组成子数组
return Quick_sort(less) + [pivot] +Quick_sort(greater)
print(Quick_sort(arr))
-----------------------------------------------------------------------
[2, 3, 5, 10]
插入排序(直接插入,希尔排序)
直接插入(Straight Insertion Sort):将一个记录插入到已经排
好序的有序表中,从而得到一个新的、记录数增 1 的有序表。
'''
步骤:
第一步,a[0]为有序区,待排序区为a[1..n-1]。令i=1。
第二步,将a[1]与a[0]中元素比较,将小的元素放在第一个位置。
第三步,以此类推,直到待排序中全部元素插入完成为止。
'''
import random
def insert_sort(nums):
"""
# 插入排序
:param nums:
:return:
"""
count = len(nums)
for i in range(1, count):
key = nums[i]
j = i - 1
while j >= 0:
if nums[j] > key:
nums[j + 1] = nums[j]
nums[j] = key
j -= 1
return nums
if __name__ == '__main__':
nums = [random.randint(1, 200) for i in range(10)]
sort_nums = insert_sort(nums)
print(sort_nums)
-------------------------------------------------------------
[6, 8, 34, 46, 50, 53, 75, 114, 160, 177]
希尔排序(Shell Sort):希尔排序是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序通过将全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
一般在记录的数量多的情况下,希尔排序的排序效率较直接插入排序高。
复杂度
ShellSort的复杂度分析非常复杂,不同gap序列的设计对应不同的复杂度。
最坏时间复杂度:根据步长序列的不同而不同。已知最好的: O(n (logn) ^2)
最优时间复杂度: O(n)
平均时间复杂度:根据步长序列的不同而不同。
选择排序(简单选择排序,堆排序)
简单选择排序:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换;接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换;重复该过程,直到进行比较的记录只有一个时为止。
"""
实现过程为:
(1)将整个记录序列划分为有序区和无序区,初始时,有序区为空,无序区含有待排序的所有记录。
(2)在无序区中选取关键码最小的记录,将它与无序区中的第一个记录交换,使得有序区扩展了一个记录,同时无序区减少了一个记录。
(3)不断重复(2),直到无序区只剩下一个记录为止。此时所有的记录已经按关键码从小到大的顺序排列。
"""
def findSmallest(arr):
smallest = arr[0]#储存最小的值
smallest_index = 0#存储最小元素的索引
for i in range(1, len(arr)):
if arr[i] < smallest:
smallest = arr[i]
smallest_index = i
return smallest_index
def selectionSort(arr):#对数组进行排序
newArr=[]
for i in range(len(arr)):
smallest=findSmallest(arr)#找出数组中最小的元素并将其加入到新数组中
newArr.append(arr.pop(smallest))
return newArr
print(selectionSort([5,3,6,2,10]))
-------------------------------------------------------------------------
[2, 3, 5, 6, 10]
堆排序: 堆排序是指利用堆积树(堆)这种数据结构所设计的一种排序算法,利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值。最大的值一定在堆顶。