1.冒泡排序
基本思想:
- 重复地走访要排序的数列,依次比较两个相邻的元素,如果他们的顺序错误就把他们交换过来。
- 走访元素的工作要重复地进行直到没有相邻元素需要交换,也就是说该数列已经排序完成。
代码实现:
void BubbleSort(vector<int>&v)
{
for (int i = 0; i < v.size()-1; i++)
{
for (int j = 0; j < v.size() - 1 - i; j++)
{
if (v[j] > v[j + 1])
{
int t = v[j];
v[j] = v[j + 1];
v[j + 1] = t;
}
}
}
}
特性总结:
- 冒泡排序属于交换排序。
- 时间复杂度:O(N^2)。
- 空间复杂度:O(1)。
- 稳定性:稳定。
2.插入排序
基本思想:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。
void InsertSort(vector<int>&v)
{
for (int i = 1; i < v.size(); i++)
{
int j;
for ( j = i - 1; j >= 0; j--)
{
if (v[i] < v[j])
v[j + 1] = v[j];
else
break;
}
v[j + 1] = v[i];
}
}
特性总结:
- 元素集合越接近有序,直接插入排序算法的时间效率越高。
- 平均时间复杂度:O(N^2)。
- 空间复杂度:O(1)。
- 稳定性:稳定。
3.希尔排序
基本思想:
把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
void ShellSort(vector<int>&v)
{
int gap = v.size();
while (1)
{
gap = (gap / 3) + 1;
for (int i = gap; i < v.size(); i++)
{
int j;
for (j = i - gap; j >= 0; j = j - gap)
{
if (v[i] < v[j])
v[j + gap] = v[j];
else
break;
}
v[j + gap] = v[i];
}
if (gap == 1)
{
break;
}
}
}
特性总结:
- 希尔排序是对插入排序的优化。
- 当 gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。整体而言,可以达到优化的效果。
- 时间复杂度:O(N ^ 1.3 ~ N ^ 2)。
- 稳定性:不稳定
4.选择排序
基本思想:
每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始(或终止)位置,直到全部待排序的数据元素排完。
void SelectSort(vector<int> &v)
{
for (int i = 0; i < v.size(); i++)
{
int max = 0;
for (int j = 0; j < v.size() - i; j++)
{
if (v[j] > v[max])
{
max = j;
}
}
int t = v[max];
v[max] = v[size - 1 - i];
v[size - 1 - i] = t;
}
}
特性总结:
- 直接选择排序非常好理解,但是效率不是很好,实际中很少使用。
- 时间复杂度:O(N^2)。
- 空间复杂度:O(1)。
- 稳定性:不稳定。
5.堆排序
基本思想:
- 堆排序是利用堆这种数据结构设计的一种排序算法,它是选择排序的一种。通过堆来进行数据选择。
- 堆是一个近似完全二叉树的结构,同时满足的性质:子结点的键值或索引总是小于(或者大于)它的父节点。
- 排升序要建大堆,排降序建小堆。
代码实现:
void Swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
void AdjustDown(int array[], int size, int r)
{
int left = 2 * r + 1;
int right = 2 * r + 2;
if (left >= size)
{
return;
}
int m = left;
if (right < size && array[right] > array[left])
{
m = right;
}
if (array[r] >= array[m])
{
return;
}
Swap(array + r, array + m);
AdjustDown(array, size, m);
}
// 建堆
void CreateHeap(int array[], int size)
{
for (int i = (size - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(array, size, i);
}
}
// 排序
void HeapSort(int array[], int size)
{
CreateHeap(array, size);
for (int i = 0; i < size; i++)
{
Swap(array, array + size - 1 - i);
AdjustDown(array, size - 1 - i, 0);
}
}
特性总结:
- 堆排序使用堆来选数,效率就高了很多。
- 时间复杂度:O(N*logN)。
- 空间复杂度:O(1)。
- 稳定性:不稳定。
- 建堆时间复杂度O(N)。