复习数据结构时,仿照王道数据结构考研复习指导,复现九大排序算法,包括插入排序(直接插入排序,折半插入排序,希尔排序),交换排序(冒泡排序,快速排序),选择排序(简单选择排序,堆排序),归并排序和基数排序。
以下算法均采用C++实现。
插入排序
直接插入排序
直接插入排序是每次将一个待排序的记录插入已经排好序的子序列,直到全部记录插入完成。
即:1.从前面的有序子表中查找出待插入元素应该被插入的位置;2.给插入位置腾出空间,将待插入元素复制到表中的插入位置
void InsertSort1(int A[], int n)
{
int i, j;
for (i = 2; i <= n; i++)
{
if (A[i] < A[i - 1])
{
//方法一
// A[0] = A[i]; // A[0]为哨兵
// for (j = i - 1; A[j] > A[0]; j--) //元素后移,寻找插入位置
// {
// A[j + 1] = A[j];
// }
// A[j + 1] = A[0];
//方法二
A[0] = A[i];
j = i - 1;
do
{
A[j + 1] = A[j];
j--;
} while (j >= 1 && A[j] > A[0]);
A[j + 1] = A[0];
}
}
}
其中,A[0]为哨兵元素。
直接插入排序:时间复杂度O(n2),空间复杂度O(1),稳定的排序算法。
折半插入排序
折半插入排序减少比较元素的次数。
void InsertSort2(int A[], int n)
{
int i, j;
for (i = 2; i <= n; i++)
{
A[0] = A[i];
int l = 1, r = i - 1;
while (l <= r) //先折半查找出元素的待插入位置,然后统一地移动待插入位置之后的所有元素
{
int mid = l + (r - l) / 2;
if (A[0] < A[mid])
r = mid - 1;
else
l = mid + 1;
}
for (j = i - 1; j >= r + 1; j--)
{
A[j + 1] = A[j];
}
A[r + 1] = A[0];
}
}
折半插入排序时间复杂度仍为O(n2),是一种稳定的排序算法。
希尔排序
希尔排序又称为缩小增量排序,即把相隔某个增量的记录组成一个子表,对各个子表分别进行直接插入排序,当整个表中的元素已经“基本有序”时,再对全体记录进行一次直接插入排序。
void shellsort(int A[], int n)
{
int i, j, dk;
for (dk = n / 2; dk >= 1; dk = dk / 2)
{
for (i = dk + 1; i <= n; i++)
if (A[i] < A[i - dk])
{
A[0] = A[i];
for (j = i - dk; j > 0 && A[j] > A[0]; j -= dk)
{
A[j + dk] = A[j];
}
A[j + dk] = A[0]; // 插入
}
}
}
希尔排序,时间复杂度约为O(n1.3),最坏情况O(n2),空间复杂度O(1),不稳定的排序。
交换排序
冒泡排序
冒泡排序,从后往前(或从前往后)两两比较相邻元素的值,若为逆序,则交换,重复n-1趟。
void BubbleSort(int A[], int n)
{
for (int i = 0; i < n - 1; i++)
{
bool flag = false;
for (int j = n - 1; j > i; j--)
{
if (A[j] < A[j - 1])
{
swap(A[j], A[j - 1]);
flag = true;
}
}
if (!flag)
return;
}
}
冒泡排序,空间复杂度O(1),时间复杂度O(n2),稳定的排序方法
快速排序
快速排序的基本思想是基于分治法的,任取一个元素pivot作为枢轴,划分为两部分。左半部分<pivot,右半部分>pivot。快速排序的partition有很多种实现方法,这里采用王道408中描述的方法进行实现。
int Partition(int A[], int low, int high)
{
int pivot = A[low];
while (low < high)
{
while (low < high && A[high] >= pivot)
high--;
A[low] = A[high]; //将比枢轴小的元素移到左端
while (low < high && A[low] <= pivot)
low++;
A[high] = A[low]; //将比枢轴大的元素移到右端
}
A[low] = pivot;
return low;
}
void QuickSort(int A[], int low, int high)
{
if (low < high)
{
int pivotpos = Partition(A, low, high);
QuickSort(A, low, pivotpos - 1);
QuickSort(A, pivotpos + 1, high);
}
}
快速排序:空间复杂度O(logn),时间复杂度O(nlogn),不稳定的排序方法,快速排序是所有内部排序算法中平均性能最优的排序算法
选择排序
简单选择排序
简单选择排序,每一趟选择关键字最小的元素,作为有序子序列的第i个元素。
void SelectSort(int A[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int min = i;
for (int j = i + 1; j < n; j++)
{
if (A[min] > A[j])
{
min = j;
}
}
if (min != i)
swap(A[min], A[i]);
}
}
选择排序,时间复杂度O(n2),空间复杂度O(1),不稳定的排序算法
堆排序
- 构造大根堆;
- 交换顶端与末尾元素,此时末尾为最大值,剩余待排序元素为n-1;
- 将剩余的n-1个数再次构成大根堆。
#include <iostream>
using namespace std;
// https://www.acwing.com/solution/content/29416/
const int N = 100010;
int h[N], mysize;
int n, m;
void down(int u)
{
int t = u;
if (2 * u <= mysize && h[t] > h[2 * u]) // 子节点小,和最小值交换
t = 2 * u;
if (2 * u + 1 <= mysize && h[t] > h[2 * u + 1])
t = 2 * u + 1;
if (t != u)
{
swap(h[t], h[u]);
down(t); // 继续向下调整
}
}
int main()
{
cin >> n >> m;
mysize = n;
for (int i = 1; i <= n; i++)
cin >> h[i];
for (int i = n / 2; i > 0; i--) // 从 n/2开始down,建立堆
down(i); // 每插入一个元素,就down
// for (int i = 1; i <= n; i++)
// cout << h[i] << " ";
// cout << endl;
while (m--) // 输出前m小的元素
{
cout << h[1] << " "; // 输出堆顶,最小值
h[1] = h[mysize--]; // 删除堆顶
down(1); // 让覆盖好的数向下走
}
cout << endl;
return 0;
}
堆排序,空间复杂度O(1),时间复杂度O(nlogn),不稳定的排序算法
归并排序
归并排序,将两个或两个以上的有序表组合成一个新的有序表,将前后相邻的两个有序表归并为一个有序表,两两进行归并。
void Merge(int A[], int left, int mid, int right)
{
int B[1001];
for (int i = left; i <= right; i++)
{
B[i] = A[i]; //将A中所有元素复制到B,辅助数组
}
int s1 = left, s2 = mid + 1, s = left; //s是指向当前位置的指针
while (s1 <= mid && s2 <= right)
{
if (B[s1] <= B[s2]) A[s++] = B[s1++];
else if (B[s1] > B[s2]) A[s++] = B[s2++];
}
while (s1 <= mid)
{
A[s++] = B[s1++]; // 若第一个表未检测完,复制
}
while (s2 <= right)
{
A[s++] = B[s2++]; // 若第二个表未检测完,复制
}
}
void MergeSort(int A[], int left, int right)
{
if (left < right)
{
int mid = (left + right) / 2;
MergeSort(A, left, mid);
MergeSort(A, mid + 1, right);
Merge(A, left, mid, right);
}
}
归并排序,空间复杂度O(n),时间复杂度O(nlogn),稳定的排序算法
基数排序
咕咕咕
内部排序方法的比较
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。