文章目录
- 1.排序定义:将一组无序的记录序列按照某种逻辑顺序重新排序,调整为有序的记录序列的过程。
- 2.排序算法的分类
- 3.常见的排序算法
- 3.1. 冒泡排序算法(遍历数组,比较相邻元素,交换位置)
- 3.2. 选择排序算法(遍历数组,找出剩余数组中最小元素,放在数组最上方)
- 3.3.插入排序算法(遍历数组,将后序无序数组中的元素插入前序有序数组中)
- 3.4.希尔排序算法
- 3.5.归并排序算法(递归地将当前序列平均分为两半,再两两合并)
- 3.6.快速排序算法(随机找一个分隔结点,与序列中其他元素比较,小的在左边,大的在右边)
- 3.7.堆排序算法(构造大顶堆,重复从大顶堆中取出最大节点)
- 3.8.计数排序算法(统计不同数值节点的个数,按照数值大小排列新的序列)
- 3.9.桶排序算法(按节点数值均匀分成n个桶,桶内排序,再依次合并)
- 3.10.基数排序算法(按整数位从低到高,遍历排序)
1.排序定义:将一组无序的记录序列按照某种逻辑顺序重新排序,调整为有序的记录序列的过程。
2.排序算法的分类
(1)按待排序的记录数量不同分为:内部排序算法(数据量不大,排序过程中全部记录放在内存中处理);外部排序算法(数据量较大,需要内存和外存之间数据交换,来实现排序目的)。
(2)按相同值的相对位置是否改变分类:稳定性排序算法(相对位置不变);非稳定性排序算法(相对位置改变)。
(3)按记录在存储介质上的组织方式分类:顺序存储结构排序算法;链式存储结构排序算法。
3.常见的排序算法
(1)O(n2) 冒泡排序算法,选择排序算法,插入排序算法
(2)O(nlogn) 希尔排序算法,归并排序算法,快速排序算法,堆排序算法
(3)O(n) 计数排序算法,桶排序算法,基数排序算法
3.1. 冒泡排序算法(遍历数组,比较相邻元素,交换位置)
3.1.1.基本思想
3.1.2.基本步骤
3.1.3.算法分析
(1)最好情况:升序排列,O(n)
(2)最差情况:降序排列,O(n2)
(3)需要移动元素次数较多,适合数据量小的情况。
(4)相邻元素交换,不会改变相同元素的相邻位置,是一种稳定性排序算法。
3.1.4.代码实现
class Solution:
def bubbleSort(self, arr):
for i in range(len(arr)):
for j in range(len(arr)):
if arr[j]>arr[j+1]:
arr[j],arr[j+1] = arr[j+1],arr[j]
return arr
3.2. 选择排序算法(遍历数组,找出剩余数组中最小元素,放在数组最上方)
3.2.1.基本思想
3.2.2.基本步骤
3.2.3.代码实现
class Solution:
def selectionSort(self, arr):
for i in range(len(arr)-1):
min_i = i
for j in range(i+1,len(arr)):
if arr[j]<arr[min_i]:
min_i = j
if i != min_i:
arr[i],arr[i+1] = arr[i+1],arr[i]
return arr
3.3.插入排序算法(遍历数组,将后序无序数组中的元素插入前序有序数组中)
3.3.1.基本思想
3.3.2.基本步骤
3.3.3.算法分析
(1)最好情况:升序排列,O(n)
(2)最差情况:降序排列,O(n2)
(3)是一种稳定性排序算法。
3.3.4.代码实现
class Solution:
def insertSort(self, arr):
for i in range(len(arr)):
temp = arr[i]
j=i
while j>0 and arr[j-1]>temp:
arr[j]=arr[j-1]
j -= 1
arr[j] = temp
return arr
3.4.希尔排序算法
3.4.1.基本思想(等价于 分层插入排序,不同的间隔代表不同的层)
3.4.2.基本步骤
3.4.3.算法分析
(1)时间复杂度为O(logn)与O(n)之间
(2)是非稳定性排序算法
3.4.4.代码实现
class Solution:
def shellSort(self, arr):
size = len(arr)
gap = size//2
while gap>0:
for i in range(gap,size):
temp = arr[i]
j=i
while j>=gap and arr[j-gap]>temp:
arr[j]=arr[j-gap]
j -= 1
arr[j] = temp
gap = gap//2
return arr
3.5.归并排序算法(递归地将当前序列平均分为两半,再两两合并)
3.5.1.基本思想
3.5.2.基本步骤
3.5.3.算法分析
(1)时间复杂度:归并的次数和每一次归并排序的时间复杂度的乘积,O(nlogn)
(2)空间复杂度:需要用到与参加排序的序列同样大小的辅助空间,O(n)
(3)是稳定性排序算法
3.5.4.代码实现
class Solution:
def merge(arr_left, arr_right):
arr=[]
while arr_left and arr_right:
if arr_left[0] <= arr_right[0]:
arr.append(arr_left.pop(0))
else:
arr.append(arr_right.pop(0))
while arr_left:
arr.append(arr_left.pop(0))
while arr_right:
arr.append(arr_right.pop(0))
return arr
def mergeSort(self, arr):
size = len(arr)
if size < 2:
return arr
mid = len(arr)//2
arr_left, arr_right = arr[0:mid], arr[mid:]
return self.merge(self.mergeSort(arr_left),self.mergeSort(arr_right))
3.6.快速排序算法(随机找一个分隔结点,与序列中其他元素比较,小的在左边,大的在右边)
3.6.1.基本思想
3.6.2.基本步骤
3.6.3.算法分析
(1)最差情况:参加排序的元素初始时已经有序,O(n2)
(2)最好情况:分界元素正好处于序列中间。O(nlogn)
(3)是一种非稳定性排序算法
3.6.4.代码实现
class Solution:
def randomPartition(self, arr:[int], low:int, high :int):
i = random.randint(low, high)
arr[i], arr[high] = arr[high], arr[i]
return self.partition(arr, low, high)
def partition(self, arr:[int], low:int, high :int):
i = low-1
pivot = arr[high]
for j in range(low, high):
if arr[j] < pivot:
i+=1
arr[i],arr[j]=arr[j],arr[i]
arr[i+1],arr[high] = arr[high],arr[i+1]
def quickSort(self, arr, low, high):
if low < high:
pi = self.randomPartition(arr, low, high)
self.quickSort(arr, low, pi-1)
self.quickSort(arr, pi+1, high)
return arr
3.7.堆排序算法(构造大顶堆,重复从大顶堆中取出最大节点)
3.7.1.基本思想
3.7.2.基本步骤
3.8.计数排序算法(统计不同数值节点的个数,按照数值大小排列新的序列)
3.8.1.基本思想
3.8.2.基本步骤
3.8.3.算法分析
(1)时间复杂度O(n+k),对于数据量很大的数组会占用很大的存储空间和时间
(2)是稳定性排序算法
3.8.4.代码实现
class Solution:
def countingSort(self, arr):
arr_min, arr_max = min(arr), max(arr)
size = arr_max - arr_min + 1
counts = [0 for _ in range(size)]
for num in arr:
counts[num-arr_min] += 1
for j in range(1, size):
counts[j] += counts[j-1]
res = [0 for _ in range(len(arr))]
for i in range(len(arr)-1,-1,-1):
res[counts[arr[i]-arr_min]-1] = arr[i]
counts[arr[i]-arr_min] -= 1
return res
3.9.桶排序算法(按节点数值均匀分成n个桶,桶内排序,再依次合并)
3.9.1.基本思想
3.9.2.基本步骤
3.9.3.算法实现
#include <iostream>
#include <vector>
#include <list>
using namespace std;
void insert(list<int>& bucket,int val)
{
auto iter = bucket.begin();
while(iter != bucket.end() && val >= *iter) ++iter;
//insert会在iter之前插入数据,这样可以稳定排序
bucket.insert(iter,val);
}
void BucketSort_1(vector<int>& arr)
{
int len = arr.size();
if(len <= 1)
return;
int min = arr[0],max = min;
for(int i=1;i<len;++i)
{
if(min>arr[i]) min = arr[i];
if(max<arr[i]) max = arr[i];
}
int k = 10;//k为数字之间的间隔
//向上取整,例如[0,9]有10个数,(9 - 0)/k + 1 = 1;
int bucketsNum = (max - min)/k + 1;
vector<list<int>> buckets(bucketsNum);
for(int i=0;i<len;++i)
{
int value = arr[i];
//(value-min)/k就是在哪个桶里面
insert(buckets[(value-min)/k],value);
}
int index = 0;
for(int i=0;i<bucketsNum;++i)
{
if(buckets[i].size())
{
for(auto& value:buckets[i])
arr[index++] = value;
}
}
}
3.9.4.算法分析
(1)时间复杂度接近O(n)
(2)是稳定性排序算法
3.10.基数排序算法(按整数位从低到高,遍历排序)
3.10.1.基本思想
3.10.2.基本步骤
3.10.3.算法分析
(1)时间复杂度O(n+k)
(2)是稳定性排序算法