排序的概念:所谓排序,就是使一串数据,按照其中的某个或某些关键字的大小,递增或递减的排序的操作。分为内部排序和外部排序两种。
内部排序:数据元素全部都放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序(在磁盘中)。
常见的排序算法有八种:直接插入排序、希尔排序、直接选择排序、堆排序、冒泡排序、快速排序、归并排序和计数排序。
以下以“7,4,5,9,8,2,1”为例,按照丛小到大升序排序。
基本思想:将需要排序的数据按其关键码值的大小逐个插入到一个已经排序好的有序序列中,直到所有数据插入完为止,得到一个新的有序序列。
当插入第 i (i >= 1)个元素时,前面那的arr[0], arr[1], …, arr[i - 1]已经排好序了,此时将arr[i]与arr[i - 1], arr[i - 2], arr[i - 3], …进行比较,插入到适当的位置。
实现代码
// 直接插入代码
#include
#include
using namespace std;
void InsertSort(vector<int>& arr, int n)
{
//总共要进行n趟,因为共n个数
for (int i = 0; i < n - 1; ++i)
{
//单趟
// 将arr[end + 1]插入到arr[0] - arr[end]中
int end = i;
int tmp = arr[end + 1];
while(end >= 0)
{
if(tmp < arr[end])
{
arr[end + 1] = arr[end];
--end;
}
else
{
break;
}
}
arr[end + 1] = tmp;
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
InsertSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 希尔排序实现代码
#include
#include
using namespace std;
void ShellSort(vector<int>& arr, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; ++i)
{
// 单趟
int end = i;
int tmp = arr[end + gap];
while (end >= 0)
{
if (tmp < arr[end])
{
arr[end + gap] = arr[end];
end -= gap;
}
else
{
break;
}
}
arr[end + gap] = tmp;
}
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
ShellSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 直接选择排序实现代码
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
void SelectSort(vector<int>& arr, int n)
{
int begin = 0, end = n - 1;
int min_index, max_index;
while (begin <= end)
{
// 单趟排序
min_index = max_index = begin;
for (int i = begin + 1; i <= end; ++i)
{
if (arr[i] < arr[min_index])
min_index = i;
if (arr[i] >= arr[max_index])
max_index = i;
}
Swap(&arr[begin], &arr[min_index]);
if (max_index == begin)
max_index = min_index;
Swap(&arr[end], &arr[max_index]);
++begin;
--end;
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
SelectSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 堆排序实现代码
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
void AdjustDown(vector<int>& arr, int n, int parent)
{
int child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && arr[child + 1] > arr[child])
++child;
if (arr[parent] < arr[child])
{
Swap(&arr[parent], &arr[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(vector<int>& arr, int n)
{
// 升序,建大根堆
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(arr, n, i);
}
// 排序
int end = n - 1;
while (end > 0)
{
Swap(&arr[0], &arr[end]);
AdjustDown(arr, end, 0);
--end;
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
HeapSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 冒泡排序实现代码
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
void BubbleSort(vector<int>& arr, int n)
{
int end = n;
while (end > 0)
{
for (int i = 1; i < end; ++i)
{
if (arr[i - 1] > arr[i])
Swap(&arr[i - 1], &arr[i]);
}
--end;
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
BubbleSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 三数取中法
#include
#include
using namespace std;
int GetMidIndex(vector<int>& arr, int left, int right)
{
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
return mid;
else if (arr[left] > arr[right])
return left;
else
return right;
}
else
{
if (arr[mid] > arr[right])
return mid;
else if (arr[left] < arr[right])
return left;
else
return right;
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
cout << GetMidIndex(vc, 0, vc.size() - 1) << endl;
cout << "基准值:" << vc[GetMidIndex(vc, 0, vc.size() - 1)] << endl;
return 0;
}
(1.)左右指针法:(左指针找比关键字大的数,右指针找,比关键字小的数)
// 快速排序的左右指针法
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
int GetMidIndex(vector<int>& arr, int left, int right)
{
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
return mid;
else if (arr[left] > arr[right])
return left;
else
return right;
}
else
{
if (arr[mid] > arr[right])
return mid;
else if (arr[left] < arr[right])
return left;
else
return right;
}
}
int PartSort1(vector<int>& arr, int left, int right)
{
//加上三数取中法来优化
int mid = GetMidIndex(arr, left, right);
Swap(&arr[mid], &arr[right]);
int key = arr[right];
int key_index = right;
while (left < right)
{
while (left < right && arr[left] <= key)
++left;
while (left < right && arr[right] >= key)
--right;
if (left < right)
{
Swap(&arr[left], &arr[right]);
++left;
--right;
}
}
Swap(&arr[left], &arr[key_index]);
return left;
}
void QuickSort1(vector<int>& arr, int left, int right)
{
if (left >= right)
return;
int index = PartSort1(arr, left, right);
QuickSort1(arr, left, index - 1);
QuickSort1(arr, index + 1, right);
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
QuickSort1(vc, 0, vc.size() - 1);
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 快速排序挖坑法
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
int GetMidIndex(vector<int>& arr, int left, int right)
{
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
return mid;
else if (arr[left] > arr[right])
return left;
else
return right;
}
else
{
if (arr[mid] > arr[right])
return mid;
else if (arr[left] < arr[right])
return left;
else
return right;
}
}
int PartSort2(vector<int>& arr, int left, int right)
{
//加上三数取中法来优化
int mid = GetMidIndex(arr, left, right);
Swap(&arr[mid], &arr[right]);
int key = arr[right];
int key_index = right;
while (left < right)
{
while (left < right && arr[left] <= key)
++left;
arr[right] = arr[left];
while (left < right && arr[right] >= key)
--right;
arr[left] = arr[right];
}
arr[left] = key;
return left;
}
void QuickSort2(vector<int>& arr, int left, int right)
{
if (left >= right)
return;
int index = PartSort2(arr, left, right);
QuickSort2(arr, left, index - 1);
QuickSort2(arr, index + 1, right);
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
QuickSort2(vc, 0, vc.size() - 1);
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 快速排序前后指针法
#include
#include
using namespace std;
void Swap(int* p, int* q)
{
int tmp = *p;
*p = *q;
*q = tmp;
}
int GetMidIndex(vector<int>& arr, int left, int right)
{
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
return mid;
else if (arr[left] > arr[right])
return left;
else
return right;
}
else
{
if (arr[mid] > arr[right])
return mid;
else if (arr[left] < arr[right])
return left;
else
return right;
}
}
int PartSort3(vector<int>& arr, int left, int right)
{
//加上三数取中法来优化
int mid = GetMidIndex(arr, left, right);
Swap(&arr[mid], &arr[right]);
int cur = left;
int prev = left - 1;
int key = arr[right];
while (cur < right)
{
if (arr[cur] < key && ++prev != cur)
Swap(&arr[prev], &arr[cur]);
++cur;
}
++prev;
Swap(&arr[right], &arr[prev]);
return prev;
}
void QuickSort3(vector<int>& arr, int left, int right)
{
if (left >= right)
return;
int index = PartSort3(arr, left, right);
QuickSort3(arr, left, index - 1);
QuickSort3(arr, index + 1, right);
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
QuickSort3(vc, 0, vc.size() - 1);
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
基本思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个营养品。将已经有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列间有序,若将两个有序表合并成一个有序表,称为二路归并。
实现代码:
(1.)递归版
// 归并排序实现代码
// 递归
#include
#include
using namespace std;
void _MergeSort(int* arr, int left, int right, int* tmp)
{
if (left == right)
return;
int mid = left + (right - left) / 2;
_MergeSort(arr, left, mid, tmp);
_MergeSort(arr, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] <= arr[begin2])
{
tmp[i++] = arr[begin1];
++begin1;
}
else
{
tmp[i++] = arr[begin2];
++begin2;
}
}
while (begin1 <= end1)
{
tmp[i++] = arr[begin1];
++begin1;
}
while (begin2 <= end2)
{
tmp[i++] = arr[begin2];
++begin2;
}
memcpy(arr + left, tmp + left, sizeof(int) * (i - left));
}
void MergeSort(int* arr, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(arr, 0, n - 1, tmp);
free(tmp);
}
int main()
{
int vc[] = { 7, 4, 5, 9, 8, 2, 1 };
MergeSort(vc, 7);
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 归并排序实现代码
// 非递归
#include
#include
using namespace std;
void MergeSort(int* arr, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
int gap = 1;
while (gap < n)
{
int i = 0;
for (int begin = 0; begin < n; begin += gap * 2)
{
int begin1 = begin, end1 = begin1 + gap - 1;
if (end1 > n - 1)
end1 = n - 1;
int begin2 = begin + gap, end2 = begin2 + gap - 1;
if (end2 > n - 1)
end2 = n - 1;
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[i++] = arr[begin1];
++begin1;
}
else
{
tmp[i++] = arr[begin2];
++begin2;
}
}
while (begin1 <= end1)
{
tmp[i++] = arr[begin1];
++begin1;
}
while (begin2 <= end2)
{
tmp[i++] = arr[begin2];
++begin2;
}
}
gap *= 2;
memcpy(arr, tmp, sizeof(int) * n);
}
}
int main()
{
int vc[] = { 7, 4, 5, 9, 8, 2, 1 };
MergeSort(vc, 7);
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
// 计数排序实现代码
#include
#include
using namespace std;
void CountSort(vector<int>& arr, int n)
{
int min = arr[0], max = arr[0];
for (int i = 0; i < n; ++i)
{
if (min > arr[i])
min = arr[i];
if (max < arr[i])
max = arr[i];
}
int range = max - min + 1;
int* tmp = (int*)malloc(sizeof(int) * range);
memset(tmp, 0, sizeof(int) * range);
// tmp为计数数组C
for (int i = 0; i < n; ++i)
{
++tmp[arr[i] - min];
}
int j = 0;
for (int i = 0; i < range; ++i)
{
while (tmp[i]--)
arr[j++] = min + i;// 重置数组,是原始数组变为数组B
}
}
int main()
{
vector<int> vc = { 7, 4, 5, 9, 8, 2, 1 };
CountSort(vc, vc.size());
for (auto e : vc)
{
cout << e << " ";
}
cout << endl;
return 0;
}
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
直接插入排序 | O(N ^ 2) | O(N) | O(N ^2) | O(1) | 稳定 |
希尔排序 | O(N * logN) - O(N ^ 2) | O(N ^ 1.3) | O(N ^2) | O(1) | 不稳定 |
直接选择排序 | O(N ^ 2) | O(N ^ 2) | O(N ^2) | O(1) | 稳定 |
堆排序 | O(N * logN) | O(N * logN) | O(N * logN) | O(1) | 不稳定 |
冒泡排序 | O(N ^ 2) | O(N) | O(N ^2) | O(1) | 稳定 |
快速排序 | O(N * logN) | O(N * logN) | O(N ^ 2) | O(logN) - O(N) | 不稳定 |
归并排序 | O(N * logN) | O(N * logN) | O(N * logN) | O(N) | 稳定 |