void InsertSort(int A[], int n){
int i, j, temp;
for (i=1; i<n; i++){
if (A[i]<A[i-1]){
temp = A[i];
for (j=i-1; j>=0 && A[j]>temp; --j){
A[j+1] = A[j];
}
A[j+1] = temp;
}
}
}
void InsertSort(int A[], int n){
int i, j;
for (i=2; i<=n; i++){
if (A[i]<A[i-1]){
A[0] = A[i];
for (j=i-1; A[0]<A[j]; --j){ // 不用每次循环都判断j>=0
A[j+1] = A[j];
}
A[j+1] = A[0];
}
}
}
void InsertSort(ing A[], int n){
int i, j, low, high, mid;
for (i=2; i<=n; i++){
A[0] = A[i];
low = 1;
high = i-1;
while (low<=high){
mid = (high+low)/2;
if (A[mid]>A[0])
high = mid - 1;
else low = mid + 1;
}
for (j=i-1; j>=high+1; --j){
A[j+1] = A[j];
}
A[high+1] = A[0];
}
}
思想:先追求表中元素部分有序,再逐渐逼近全局有序
这里的A[0]只是暂存单元,不是哨兵(循环语句中会判断若j<=0就到了插入位置)
void ShellSort(int A[], int n){
int d, i, j;
for (d=n/2; d>=1; d=d/2)
for (i=d+1; i<=n; ++i)
if (A[i]<A[i-d]{
A[0] = A[i];
for (j=i-d; j>0 && A[0]<A[j]; i-=d)
A[j+d] = A[j]; // 同组的记录后移,找寻当前元素的插入位置
A[j+d] = A[0];
}
}
每一趟都能使最小的元素被放在最终位置(也可以改动以下代码使每一趟把最大的元素被放在最终位置)
void swap(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
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-1]>A[j]){
swap(A[j-1], A[j]);
flag = true;
}
if (flag==false)
return;
}
}
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);
}
}
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 SelectSort(int A[], int n){
for (int i=0; i<n-1; i++){
int min = i;
for (int j=i+1; i<n; j++){
if (A[j]<A[min])
min = j;
}
if (min!=i)
swap(A[i], A[min]);
}
}
void swap(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
先建堆,再排序。建堆时让编号 ≤ n 2 \le\frac{n}{2} ≤2n的所有节点依次下坠(自底向上调整各分支节点),下坠规则就是小元素与关键字更大的孩子交换位置。排序时让堆顶元素加入有序子序列(大根堆排序时是让堆顶元素与堆底元素交换),堆底元素换到堆顶后,进行下坠调整,恢复大根堆的特性。将排序过程重复n-1趟
void BuildMaxHeap(int A[], int len){
for (int i=len/2; i>0; i--) // 从后向前调整所有非终端节点
HeadAdjust(A, i, len);
}
// 将以k为根的子树调整为大根堆(即小元素下坠过程)
void HeadAdjust(int A[], int k, int len){
A[0] = A[k]; // A[0]的作用为暂存子树根节点(即要下坠的那个小元素)
for (int i=2*k; i<=len; i*2){ // 让i先指向当前节点左孩子
if (i<len && A[i]<A[i+1])
i++;
if (A[0]>=A[i]) break;
else{
A[k] = A[i];
k = i;
}
}
A[k] = A[0];
}
这里有个常考考点:若一个节点有两个孩子,则其“下坠”一层,需要对比关键字两次(孩子对比选最大,该节点再与大孩子对比);若下方只有一个孩子,则“下坠”一层只需对比关键字1次
void HeapSort(int A[], int len){
BuildMaxHeap(A, len);
for (int i=len; i>1; i--){
swap(A[i], A[1];
HeadAdjust(A, 1, i-1);
}
}
归并即把两个或多个已经有序的序列合并成一个
int *B = (int *)malloc(n*sizeof(int)); // 辅助数组B
void Merge(int A[], int low, int mid, int high){
int i, j, k;
for (k=low; k<=high; k++)
B[k] = A[k]; // 将A中所有元素复制到B中
for (i=low, j=mid+1, k=i; i<=mid&&j<=high; k++){
if (B[i]<=B[j])
A[k] = B[i++];
else
A[k] = B[j++];
}
while (i<=mid)
A[k++] = B[i++];
while (j<=high)
A[k++] = B[j++];
}
void MergeSort(int A[], int low, int high){
if (low<high){
int mid = (low+high)/2;
MergeSort(A, low, mid); // 对左半部分归并排序
MergeSort(A, mid+1, high); // 对右半部分归并排序
Merge(A, low, mid, high); // 归并
}
}
基数排序不是基于比较的排序算法
只考手动模拟,几乎不考代码
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
} LinkNode, *LinkList;
typedef struct{
LinkNode *front, *rear;
} LinkQueue;
算法 | 空间复杂度 | 时间复杂度 | 算法稳定性 | 适用性 |
---|---|---|---|---|
插入排序 | O ( 1 ) O(1) O(1) | 最好 O ( n ) O(n) O(n);最坏 O ( n 2 ) O(n^2) O(n2);平均 O ( n 2 ) O(n^2) O(n2) (主要来自对比关键字、移动元素,若有n个元素,需要n-1趟处理) | 稳定 | |
折半插入排序 | O ( 1 ) O(1) O(1) | 最好 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n);最坏 O ( n 2 ) O(n^2) O(n2);平均 O ( n 2 ) O(n^2) O(n2) | 稳定 | |
希尔排序 | O ( 1 ) O(1) O(1) | 最坏 O ( n 2 ) O(n^2) O(n2) | 不稳定 | 仅适用于顺序表,不适用于链表 |
冒泡排序 | O ( 1 ) O(1) O(1) | 最好 O ( n ) O(n) O(n)(有序);最坏 O ( n 2 ) O(n^2) O(n2)(逆序);平均 O ( n 2 ) O(n^2) O(n2) | 稳定 | 适用于顺序表和链表 |
快速排序 | 最好 O ( l o g 2 n ) O(log_2n) O(log2n);最坏 O ( n ) O(n) O(n) | 最好 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)(每次选的pivot都能将序列分成均匀的两部分);最坏 O ( n 2 ) O(n^2) O(n2)(初始有序或逆序);平均 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | 不稳定 | 适用于顺序表,不适用于链表 |
简单选择排序 | O ( 1 ) O(1) O(1) | O ( n 2 ) O(n^2) O(n2) | 不稳定 | 顺序表、链表都可以 |
堆排序 | O ( 1 ) O(1) O(1) | 建堆 O ( n ) O(n) O(n)、排序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),总时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | 不稳定 | |
归并排序 | O ( 1 ) O(1) O(1) | 每一趟的对比次数 O ( n ) O(n) O(n)、趟数 O ( l o g 2 n ) O(log_2n) O(log2n),总时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) | 稳定 | |
基数排序 | O ( r ) O(r) O(r) | O ( d ( n + r ) ) O(d(n+r)) O(d(n+r)),其中数据元素的关键字拆分为d组,每组关键字的取值范围为r,数据元素个数为n | 稳定 |