1. 直接插入排序
void insertSort(int q[],int n){
int i, j, temp;
for (i = 2; i <= n; i++) {
//当有序区间的最后一个元素大于当前元素时
if (q[i-1] > q[i]) {
temp = q[i];
for (j = i-1; j >= 0 && q[j] > temp; j--){//升序排序
q[j+1] = q[j];
}
q[j+1] = temp;
}
}
}
控件复杂度:O(1)
时间复杂度:O(n2)
最好情况:数组已有序,此时没插入一个元素,只需要比较而不用移动元素,为O(n)
最坏情况:数组为逆序,比较次数最大为 ∑ i = 2 n i \sum_{i=2}^{n} i i=2∑ni = n ( n − 1 ) n \frac{n(n - 1)}{n} nn(n−1) = O(n2),移动次数最大为 ∑ i = 2 n ( i + 1 ) \sum_{i=2}^{n} (i + 1) i=2∑n(i+1) = ( n − 1 ) ( n + 4 ) 2 \frac{(n - 1)(n + 4)}{2} 2(n−1)(n+4) = O(n2)
是否稳定:是
2. 折半插入排序
void binInserSort(int q[],int n){
int i, j, temp;
for (i = 2; i <= n; i++) {
if (q[i-1] > q[i]) {
temp = q[i];
//二分查找有序区间[0,i-1]
int l = 0, r = i - 1;
while (l <= r) {
int mid = l + r >> 1;
if (q[mid] > temp) r = mid - 1; //在左半区
else l = mid + 1; //在右半区
}
for (j = i - 1; j >= r + 1; j--) {
q[j+1] = q[j];
}
q[j+1] = temp;
}
}
}
空间复杂度:O(1)
时间复杂度:O(n2)
仅减少了比较元素的次数,约为O(nlog2n),移动次数未改变
是否稳定:是
3. 希尔排序
void shellSort(int q[],int n) { //希尔排序
int i, j, d, temp;
//进行分组,最开始的增量d为数组长度的一半
for (d = n/2; d > 0; d /= 2) {
//对各个分组进行插入排序
for (i = d; i <= n; i++) {
temp = q[i];
//插入的时候按组进行插入(组内的相邻元素物理地址上相隔d)
for (j = i - d; j >= 0 && q[j] > temp; j -= d) {
q[j + d] = q[j];
}
q[j + d] = temp;
}
}
}
空间复杂度:O(1)
时间复杂度:O(n1.3)
希尔排序时间复杂度难以分析,一般约为O(n1.3);最坏为O(n2)
是否稳定:否
4. 冒泡排序
void bubbleSort(int q[],int n) { //冒泡排序
for (int i = 1; i < n; i++) {
bool flag = false;
for (int j = n; j > i; j--) {
if (q[j-1] > q[j]) { //若为逆序
swap(q[j-1], q[j]);
flag = true;
}
}
if(!flag) return; //本次没有发生交换,中途结束算法
}
}
空间复杂度:O(1)
时间复杂度:O(n2)
最好情况:数组已有序,比较次数为O(n),移动次数为0
最坏情况:数组为逆序,比较次数最大为 ∑ i = 1 n − 1 ( n − i ) \sum_{i=1}^{n-1} (n-i) i=1∑n−1(n−i) = n ( n − 1 ) 2 \frac{n(n - 1)}{2} 2n(n−1) = O(n2),移动次数最大为 ∑ i = 1 n − 1 3 ( n − i ) \sum_{i=1}^{n-1} 3(n - i) i=1∑n−13(n−i) = 3 n ( n − 1 ) 2 \frac{3n(n - 1)}{2} 23n(n−1) = O(n2)
是否稳定:是
5. 快速排序
void quickSort(int q[],int l,int r) {
if(l >= r) return;
int i = l-1, j = r+1,x = q[l+r >> 1];
while (i < j) {
while (q[++i] < x);
while (q[--j] > x);
if (i < j) swap(q[i], q[j]);
}
swap( q[l], q[j]);
quickSort(q,l, j);
quickSort(q,j + 1, r);
}
空间复杂度:O(log2n)
最好情况:每次都将n个元素划分为两次长度差不多相同的子区间,为O(log2n)
最坏情况:划分的两个区间分别包含0个和n-1个元素,为O(n)
时间复杂度:O(n2)
最好情况:每次都将n个元素划分为两次长度差不多相同的子区间,为O(nlog2n)
最坏情况:划分的两个区间分别包含0个和n-1个元素,为O(n2)
是否稳定:否
6. 简单选择排序
void seleSort(int q[],int n) {
int i, j, temp, min;
for (i = 1; i < n; i++) {
min = i; //记录最小元素下标
//从q[i,n-1]中选择最小元素,因为q[0,i]已排好序
for (j = i+1; j <= n; j++) {
if (q[min] > q[j])
min = j;
}
if(min != i) swap(q[i], q[min]);
}
}
空间复杂度:O(1)
时间复杂度:O(n2)
最好情况:数组已有序,比较次数无论好坏均为 n ( n − 1 ) 2 \frac{n(n - 1)}{2} 2n(n−1),移动次数为0
最坏情况:数组为逆序,移动次数为3(n-1)
是否稳定:否
7. 堆排序
void down(int u,int size) //堆的区间长度[1...size]
{
int temp = q[u]; //将q[i]存为子树的根节点
for(int j = u*2;j <= size ;j *= 2)
{
//如果u有右孩子,并且右孩子值比左孩子大,则将j指向右孩子
if(j+1 <= size && q[j] < q[j+1]) j++;
//如果u的孩子的最大值比自身大,则将j与u的位置交换
if(q[j] > temp)
{
q[u] = q[j];
u = j;
}
else break;
}
q[u] = temp; //将q[u]的值放置在合适位置
}
//构造大根堆
void heapSort(int q,int n){
for(int i = n/2;i > 0;i--) down(i,n);
swap(q[1],q[n]); //此时q[1]为堆区间最大值,将其移到最后
for(int i = n-1;i > 0;i--){ //执行n-1次操作
down(1,i);
swap(q[1],q[i]);
}
}
空间复杂度:O(1)
时间复杂度:O(nlog2n)
是否稳定:否
8. 归并排序
int t[N];
void merging(int q[],int low,int mid,int high) { //归并操作
int k = low;
int l,r;
for (l = low, r = mid + 1; l <= mid && r <= high; ) {
if (q[l] <= q[r]) t[k++] = q[l++];
else t[k++] = q[r++];
}
while (l <= mid) t[k++] = q[l++];
while (r <= high) t[k++] = q[r++];
for (l = low; l <= high; l++) q[l] = t[l];
}
void mergeSort(int q[],int low ,int high) {
if (low >= high) return;
int mid = (low + high) / 2; //从中间划分区间
mergeSort(q,low, mid); //排列左区间
mergeSort(q,mid + 1, high); //排列右区间
merging(q,low, mid, high); //归并左右区间
}
空间复杂度:O(n),辅助数组大小最大为n
时间复杂度:O(nlog2n)
每次归并时间为O(n),共需要进行log2n趟归并
是否稳定: 是