基本的排序算法
- 选择排序
- 冒泡排序
- 插入排序
- 快速排序
- 合并排序
- 基数排序
- 堆排序
选择排序
算法思路:假设A[1…n]是一个有n个元素的数组。
- 首先从A[1…n]找到最小元素,将其放在A[1]中
- 从A[2…n]中找到最小元素,将其放在A[2]中
- 重复A[i…n]中找到最小元素,将其放在A[i]中
- 直至i=n-1
元素比较次数: ∑ni=1(n−i)=∑ni=1i=n(n−1)/2
时间复杂度为
O(n2)
不稳定排序
代码实现:
void selectionSort(int arr[], int len)
{
int k, temp;;
for (int i = 0; i < len-1; i++)
{
k = i;
for (int j = i + 1; j < len; j++)
{
if (arr[j] < arr[k])
k = j;
}
if (k != i)
{
temp = arr[k];
arr[k] = arr[i];
arr[i] = temp;
}
}
}
冒泡排序
算法思路:假设A[1…n]是一个有n个元素的数组。
- 从A[n]向前遍历直至A[ 1 ],如果A[j]小于A[j-1],A[j]与A[j-1]交换,依次遍历,A[1]为最小元素
- 从A[n]向前遍历直至A[ 2 ],类似1
- 直到所有元素都以非降序排列,或前n-1个元素都已排序
元素比较次数: ∑ni=1(n−i)=∑ni=1i=n(n−1)/2
时间复杂度为
O(n2)
稳定排序
代码实现:
void bubbleSort(int arr[], int len)
{
bool flag = true;
int i, j, temp;
for (i = 0; i < len - 1; i++)
{
for (j = len - 1; j>i; j--)
{
if (arr[j] < arr[j - 1])
{
flag = false;
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
if (flag) //如果所有元素均已有序,直接跳出循环
break;
}
}
插入排序
算法思路:假设A[1…n]是一个有n个元素的数组
- 从大小为1的子数组A[ 1 ]开始,将A[ 2 ]插入到A[ 1 ]的前面或后面,完成一次排序。
- 重复以下过程:将A[i]插入到已排序的子数组A[1…i-1]中合适位置。
- 直至i=n
元素比较次数: ∑ni=2(i−1)=∑n−1i=1i=n(n−1)/2
时间复杂度为
O(n2)
稳定排序
代码实现:
void insertSort(int arr[], int len)
{
int i, j, temp;
for (i = 1; i < len; i++)
{
temp = arr[i];
j = i - 1;
while (j >= 0 && arr[j]>temp) //循环遍历arr[0...i-1],将arr[i]插入合适位置
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
}
快速排序
算法思路:
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
平均时间复杂度为
O(nlog2n)
,最坏时间复杂度为
O(n2)
不稳定排序
代码实现:
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
int mid, l, r, temp;
l = low, r = high;
temp = arr[high];
while (l < r)
{
while (l<r&&arr[l] <= temp)
l++;
if (l < r)
arr[r] = arr[l];
while (l<r&&arr[r] >= temp)
r--;
if (l < r)
arr[l] = arr[r];
}
arr[l] = temp;
mid = l;
quickSort(arr, low, mid - 1);
quickSort(arr, mid + 1, high);
}
}
合并排序
算法思路:自顶向下,不断将数组分成两半,直至每部分只有一个元素。再合并两部分已排好序的的数组成为一个数组。
平均时间复杂度为
O(nlog2n)
稳定排序
代码实现:
void Merge(int arr[], int low, int mid, int high)
{
int len = high - low + 1;
int *copy = new int[len];
int i = low, j = mid + 1, k = low;
while (i <= mid&&j <= high)
{
if (arr[i] <= arr[j])
copy[k - low] = arr[i++];
else
copy[k - low] = arr[j++];
k++;
}
if (i == mid + 1)
{
for (int ii = j; ii <= high; ii++)
{
copy[k - low] = arr[ii];
k++;
}
}
else
{
for (int ii = i; ii <= mid; ii++)
{
copy[k - low] = arr[ii];
k++;
}
}
for (i = low; i <= high; i++)
{
arr[i] = copy[i - low];
}
}
void mergeSort(int arr[], int low, int high)
{
if (low < high)
{
int mid = floor((low + high) / 2);
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
Merge(arr, low, mid, high);
}
}
堆排序
创建堆:时间复杂度为
O(n)
堆排序:平均时间复杂度为
O(nlog2n)【建堆
O(n)
,siftdown运算
O(log2n)
时间,重复n-1次】
不稳定排序
代码实现:
void SiftDown(int arr[], int len, int idx)
{
bool done = false;
int par, temp;
if (idx * 2 >= len)
return;
while (2 * idx < len && done==false)
{
par = idx;
idx = 2 * idx;
if (idx + 1 < len&&arr[idx + 1] > arr[idx]) //对比左右子结点,找较大值
idx = idx + 1;
if (arr[par] < arr[idx])
{
temp = arr[idx];
arr[idx] = arr[par];
arr[par] = temp;
}
else
done = true;
}
}
void makeHeap(int arr[], int len)
{
int k = floor((len - 1) / 2);
for (int i = k; i >= 0; i--)
{
SiftDown(arr, len, i);
}
}
void heapSort(int arr[], int len)
{
makeHeap(arr, len);
for (int i = 0; i<len; i++)
cout << arr[i] << " ";
cout << endl;
for (int i = len - 1; i > 0; i--)
{
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
SiftDown(arr, --len, 0);
}
}
基数排序
算法思路:假设L={a1,a2,a3…an}是一个有n个元素的表,其中每个元素恰好有k位数字,即 dkdk−1...d1, di 是0-9的数字。
- 首先根据 d1 位,把表中所有元素分到 L0,L1,...L9 中,即 d1=0 的数分到 L0 中, d1=1 的数分到 L1 中,等等。
- 按照 d2 分到10张表中,按顺序连接起来。
- 依次进行到 dk ,即可完成排序。
时间复杂度为
O(kn)
稳定排序
举例:下面为8个四位数
初始 | 第 一次 | 第二次 | 第三次 | 第四次 |
---|---|---|---|---|
7467 | 679 2 | 93 1 4 | 9 1 34 | 1 239 |
1247 | 913 4 | 12 3 9 | 9 1 87 | 1 247 |
3275 | 327 5 | 12 4 7 | 1 2 39 | 3 275 |
6792 | 467 5 | 74 6 7 | 1 2 47 | 4 675 |
9187 | 746 7 | 32 7 5 | 3 2 75 | 6 792 |
9134 | 124 7 | 46 7 5 | 7 4 67 | 7 467 |
4675 | 918 7 | 91 8 7 | 4 6 75 | 9 134 |
1239 | 123 9 | 67 9 2 | 6 7 92 | 9 187 |