具体可以参考(有动图演示很好理解):传送门
1.冒泡排序
冒泡排序还可以用来求逆序数,我们知道冒泡排序每一次的交换原序列逆序数减1,所以我们只需要统计交换了多少次即可得知这个序列的逆序数
冒泡排序可以是稳定的排序也可以是不稳定的排序,看自己的写法
void bubbleSort (int arr[], int n) {
for (int i = 0; i < n; ++i) {
for (int j = 1; j < n - i; ++j) {
if (arr[j - 1] > arr[j]) {
int tmp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = tmp;
}
}
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
bubbleSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
2.选择排序
每次选择当前未排序序列中最小的放到已经排序好的序列的尾端,注意它是不稳定排序
比如 4,4,1,2 很显然我们第一趟排序之后变成 1, 4, 4, 2 原本第一个4到了原本第二个4的后面
void selectionSort (int arr[], int n) {
for (int i = 0; i < n; ++i) {
int id = i;
for (int j = i; j < n; ++j) {
if (arr[id] > arr[j]) {
id = j;
}
}
int tmp = arr[id];
arr[id] = arr[i];
arr[i] = tmp;
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
selectionSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
3.插入排序
数组前部分是已经排序好的,后部分是待排序的,每次排序待排序数组中的第一个,然后和已经排序的数组进行比较,直到插入到合适的位置
其实也类似冒泡排序,也属于稳定排序
void insertSort (int arr[], int n) {
for (int i = 1; i < n; ++i) {
int j = i;
while (j > 0 && arr[j] < arr[j - 1]) {
int tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
j--;
}
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
insertSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
4.希尔排序
算法思想就是在插入排序的情况下尽量减少向前移动的次数
因为这个涉及到间隔排序,所以这也是不稳定的排序算法
void shellSort (int arr[], int n) {
int gap = (n >> 1);
while (gap > 0) {
for (int i = 0; i < gap; ++i) {
for (int j = i + gap; j < n; j += gap) {
for (int k = j; k - gap >= 0; k -= gap) {
if (arr[k] < arr[k - gap]) {
int tmp = arr[k];
arr[k] = arr[k - gap];
arr[k - gap] = tmp;
}
}
}
}
gap >>= 1;
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
shellSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
5.快速排序
如果数据是 1 1 1 1 1这样的,快排可以退化到O(n^2)的复杂度
int Sort (int arr[], int l, int r) {
int i = l, j = r;
int x = arr[l];
while (i < j) {
while (i < j && arr[j] >= x) --j;
arr[i] = arr[j];
while (i < j && arr[i] <= x) ++i;
arr[j] = arr[i];
}
arr[i] = x;
return i;
}
void quickSort (int arr[], int l, int r) {
if (l < r) {
int mid = Sort(arr, l, r);
quickSort(arr, l, mid);
quickSort(arr, mid + 1, r);
}
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
quickSort(arr, 0, sizeof(arr) / sizeof(int) - 1);
for (int i = 0; i < sizeof(arr) / sizeof(int); ++i) {
printf("%d ", arr[i]);
}
puts("");
return 0;
}
6.归并排序
稳定不稳定取决你怎么写
void Sort (int arr[], int l, int r, int mid) {
int i = l, j = mid + 1;
int tmp[r - l + 5];
int cnt = 0;
while (i <= mid && j <= r) {
if (arr[i] <= arr[j]) {
tmp[cnt++] = arr[i++];
} else {
tmp[cnt++] = arr[j++];
}
}
while (i <= mid) {
tmp[cnt++] = arr[i++];
}
while (j <= r) {
tmp[cnt++] = arr[j++];
}
for (int i = l; i <= r; ++i) {
arr[i] = tmp[i - l];
}
}
void mergeSort (int arr[], int l, int r) {
if (l < r) {
int mid = (l + r) >> 1;
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
Sort(arr, l, r, mid);
}
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
mergeSort(arr, 0, sizeof(arr) / sizeof(int) - 1);
for (int i = 0; i < sizeof(arr) / sizeof(int); ++i) {
printf("%d ", arr[i]);
}
puts("");
return 0;
}
7.堆排序
void Sort (int arr[], int start, int end) {
int dad = start;
int son = dad * 2 + 1;
while (son < end) {
if (son + 1 < end && arr[son] < arr[son + 1]) {
son++;
}
if (arr[dad] >= arr[son]) {
return ;
}
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
void heapSort (int arr[], int n) {
for (int i = (n - 1) / 2; i >= 0; --i) {
Sort(arr, i, n);
}
for (int i = n - 1; i > 0; --i) {
swap(arr[i], arr[0]);
Sort(arr, 0, i);
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
heapSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
还有三种找时间再写、
8.计数排序
时间复杂度O(n + k),k是待排序数组中的最大值,是一种稳定排序,但是需要开辟一段额外辅存
void countingSort (int arr[], int n) {
int maxn = 0;
for (int i = 0; i < n; ++i) {
maxn = max(maxn, arr[i]);
}
int basket[maxn + 5];
mst(basket, 0);
for (int i = 0; i < n; ++i) {
basket[arr[i]]++;
}
int cnt = n;
for (int i = maxn; i >= 0; --i) {
while (basket[i] > 0) {
basket[i]--;
arr[--cnt] = i;
}
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
return ;
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4};
countingSort(arr, sizeof(arr) / sizeof(int));
return 0;
}
9.基数排序
时间复杂度O(2 * n * maxDijit),另外开需要开辟n个空间的辅存,属于稳定排序,
void radixSort (int arr[], int n) {
int maxDigit = 1;
for (int i = 0; i < n; ++i) {
int tmp = arr[i];
int cnt = 0;
while (tmp > 0) {
tmp /= 10;
cnt++;
}
maxDigit = max(maxDigit, cnt);
}
printf("%d\n", maxDigit);
int dev = 1;
int mod = 10;
vector<int> vt[10];
for (int i = 0; i < maxDigit; ++i, dev *= 10) {
for (int j = 0; j < n; ++j) {
int bucket = (arr[j] / dev) % mod;
vt[bucket].push_back(arr[j]);
}
int pos = 0;
for (int j = 0; j < 10; ++j) {
for (int k = 0; k < (int)vt[j].size(); ++k) {
arr[pos++] = vt[j][k];
}
vt[j].clear();
}
}
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
puts("");
return ;
}
int main() {
int arr[] = {3, 2, 1, 5, 7, 9, 6, 8, 4, 100, 19, 400, 3000, 20};
radixSort(arr, sizeof(arr) / sizeof(int));
return 0;
}