排序算法总结
排序算法
排序算法比较
排序算法 | 平均时间复杂度 | 最差时间复杂度 | 空间复杂度 | 数据对象稳定性 |
---|---|---|---|---|
冒泡排序 | O(n2) | O(n2) | O(1) | 稳定 |
选择排序 | O(n2) | O(n2) | O(1) | 数组不稳定,链表稳定 |
插入排序 | O(n2) | O(n2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(n2) | O(log2n) | 不稳定 |
归并排序 | O(nlog2n) | O(nlog2n) | O(n) | 稳定 |
希尔排序 | O(nlog2n) | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(1) | |
计数排序 | O(n+k) | O(m+n) | O(k) | 稳定 |
桶排序 | O(n+k) | O(n) | O(n+k) | 稳定 |
基数排序 | O(n*k) | O(n2) | O(n+k) | 稳定 |
锦标赛排序 |
起泡排序
- 起泡排序思路:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
void swap(int & a, int & b) {
int c = a;
a = b;
b = c;
}
int bubble(int *num, int m) {
int flag = 0;
for (int i = 1; i < m; i++) {
if (num[i-1] > num[i]) {
swap(num[i-1], num[i]);
flag = i;
}
}
return flag;
}
void bubbleSort(int *num, int n) {
int fl = bubble(num, n);
while (fl) {
fl = bubble(num, fl);
}
}
选择排序
- 选择排序思路:
- 在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
- 从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾
- 以此类推,直到所有元素均排序完毕
void SelectionSort(vector<int>& v) {
int min, len = v.size();
for (int i = 0; i < len - 1; ++i) {
min = i;
for (int j = i + 1; j < len; ++j) {
if (v[j] < v[min]) { // 标记最小的
min = j;
}
}
if (i != min) // 交换到前面
swap(v[i], v[min]);
}
}
// 模板实现
template<typename T>
void Selection_Sort(std::vector<T>& arr) {
int len = arr.size();
for (int i = 0; i < len - 1; i++) {
int min = i;
for (int j = i + 1; j < len; j++)
if (arr[j] < arr[min])
min = j;
if(i != min)
std::swap(arr[i], arr[min]);
}
}
插入排序
- 插入排序思路:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
void InsertSort(vector<int>& v)
{
int len = v.size();
for (int i = 1; i < len - 1; ++i) {
int temp = v[i];
for(int j = i - 1; j >= 0; --j)
{
if(v[j] > temp)
{
v[j + 1] = v[j];
v[j] = temp;
}
else
break;
}
}
}
快速排序
- 快速排序思路:
- 选取第一个数为基准
- 将比基准小的数交换到前面,比基准大的数交换到后面
- 对左右区间重复第二步,直到各区间只有一个数
int partition(vector<int> & num, int lo, int hi) {
int pivot = num[lo];
int temp = lo;
while (lo < hi) {
while ((lo < hi) && (pivot <= num[hi]))
hi--;
num[lo] = num[hi];
while ((lo < hi) && (pivot >= num[lo]))
lo++;
num[hi] = num[lo];
//std::swap(num[hi], num[lo]);
}
num[lo] = pivot;
//std::swap(num[lo], num[temp]);
//for (auto w : num)
// cout << w << " ";
//cout << endl;
return lo;
}
void quickSo(vector<int> & num, int lo, int hi) {
if (hi - lo < 2)
return;
int mi = partition(num, lo, hi - 1);
quickSo(num,lo, mi);
quickSo(num,mi + 1, hi);
}
void quickSort(vector<int> & num) {
quickSo(num, 0, num.size());
}
// ----------------------------------------------------
// 模板实现快速排序(迭代)
struct Range {
int start, end;
Range(int s = 0, int e = 0) {
start = s, end = e;
}
};
template <typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
void quick_sort(T arr[], const int len) {
if (len <= 0)
return; // 避免len等於負值時宣告堆疊陣列當機
// r[]模擬堆疊,p為數量,r[p++]為push,r[--p]為pop且取得元素
Range r[len];
int p = 0;
r[p++] = Range(0, len - 1);
while (p) {
Range range = r[--p];
if (range.start >= range.end)
continue;
T mid = arr[range.end];
int left = range.start, right = range.end - 1;
while (left < right) {
while (arr[left] < mid && left < right) left++;
while (arr[right] >= mid && left < right) right--;
std::swap(arr[left], arr[right]);
}
if (arr[left] >= arr[range.end])
std::swap(arr[left], arr[range.end]);
else
left++;
r[p++] = Range(range.start, left - 1);
r[p++] = Range(left + 1, range.end);
}
}
归并排序
- 核心思想:分而治之
- 实现步骤:
void MergeSort(){
递归条件
分组1
分组2
归并
}
template<typename T>
void merge(vector<T> &num, int lo, int mi, int hi) {
int lb = mi - lo;
int lc = hi - mi;
T *pa = &num[lo];
T *pb = new T[lb];
T *pc = &num[mi];
for (int i = 0; i < lb; i++) {
pb[i] = pa[i];
}
for (int m = 0, n = 0, k = 0; (m < lb) || (n < lc);) {
if ((m < lb) && ((n >= lc) || (pb[m] < pc[n])))
pa[k++] = pb[m++];
else
pa[k++] = pc[n++];
}
}
template <typename T>
void mergeSort(vector<T> & A,int lo, int hi) {
if (hi - lo < 2) //递归条件
return;
int mi = (hi + lo) >> 1;
mergeSort(A,lo, mi);
mergeSort(A,mi, hi);
merge(A,lo, mi, hi);
}
template<typename T>
void merge_sort(T arr[], int len) {
T* a = arr;
T* b = new T[len];
for (int seg = 1; seg < len; seg += seg) {
for (int start = 0; start < len; start += seg + seg) {
int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
int k = low;
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
while (start1 < end1 && start2 < end2)
b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
while (start1 < end1)
b[k++] = a[start1++];
while (start2 < end2)
b[k++] = a[start2++];
}
T* temp = a;
a = b;
b = temp;
}
if (a != arr) {
for (int i = 0; i < len; i++)
b[i] = a[i];
b = a;
}
delete[] b;
}
希尔排序
算法思想:
算法思想来源于插入排序,
先将n个待排序的序列分割成n/2组数据分别进行插入排序,
然后依次分割成n/4组,n/8组,
直至最后只能分成一组数据进行插入排序
算法演示:
算法实现:
//希尔排序
void shellSort(int *p, int n) {
int temp = n;
while (temp >>= 1) {
for (int i = temp; i < n; i++) {
for (int j = i; j > 0; j -= temp) {
if (p[j] < p[j - temp]) {
Swap(p[j], p[j - temp]);
break;
}
}
}
}
}
计数排序
算法思想:
对值比较集中的数据进行排序先统计每个数据个数,再根据个数进行排序
算法图解
算法实现
//计数排序
void countSort(int *p, int n) {
int max = p[0];
int min = p[0];
for (int i = 0; i < n; i++) { //找到最小与最大值
if (max < p[i])
max = p[i];
if (min > p[i])
min = p[i];
}
int space = max - min + 1;
int *num = new int[space](); //申请辅助空间
for (int i = 0; i < n; i++) { //统计
num[p[i] - min]++;
}
int j = 0;
for (int i = 0; i < space; i++) { //排序
while (num[i]--) {
p[j++] = i+min;
}
}
delete[]num;
}
桶排序
基数排序