写这个博客的主要是因为总是感觉自己的算法学的不够扎实,所以打算写下来加强自己的理解。
插入排序
思想:在一个已经有序的小序列基础上,一次插入一个元素。
性质: 平均最坏情况都是 O(n2) ,最好情况是已排序 O(n) , 遇到相等元素,每次都插入在相等的之后,所以是稳定的, 辅助空间 O(1)
void insert(int *array, int n){
int j, key;
for(int i = 1; i < n; i++){
key = array[i];
for(j = i; j > 0 && array[j - 1] > key; j--){
array[j] = array[j - 1];
}
array[j] = key;
}
}
另一种写法,循环控制不同, 注意边界
void insert(int * array, int n){
int key, j;
for(int i = 1; i < n; i++){
key = array[i];
j = i -1;
while(j >= 0 && array[j] > key){
array[j+1] = array[j];
j--;
}
array[j+1] = key;
}
}
选择排序
思想:第一次从中选出最小的,第二次次小,第三次再小,以此类推
性质:平均最坏情况都是 O(n2) ,最好情况是已排序 O(n2) ,, 辅助空间 O(1) , 不稳定
void select(int array[], int n){
int i,j, k, tmp;
for(i = 0; i < n; i++){
k = i;
for(j = i + 1; j < n; j++){
if(array[k] > array[j])
k = j;
}
if(k != i){
tmp = array[k]; array[k] = array[i]; array[i] = tmp;
}
}
}
冒泡排序
思想:不断把最小的往前面调整,或者把最大向后调整
性质:平均最坏情况都是 O(n2) ,最好情况是已排序 O(n) , 只改变相邻的元素,所以稳定, 辅助空间 O(1)
void bubble(int array[], int n){
int i, j, tmp;
for(i = 0; i < n; i++){
for(j = 0; j < n - i - 1; j++){
if(array[j] > array[j + 1]){
tmp = array[j]; array[j] = array[j + 1]; array[j + 1] = tmp;
}
}
}
}
归并排序
思想:顾名思义,将已经有序的合并起来,合并之前要将数组划分开成很多小段
性质:平均、最好、最好情况下都是
O(nlog2n)
, 辅助空间为
O(n)
, 由于分割到最后一个元素或者两个元素的时候,即使相等没有交换,所以稳定
// 假设array[low... mid]和array(mid, end]都是有序数组,将二者合并成一个有序数组
void merge(int array[], int low, int mid, int end){
int n1 = mid - low + 1, n2 = end - mid, i, j, k;
int arr1[n1], arr2[n2];
for(i = 0; i < n1; i++)
arr1[i] = array[low + i];
for(i = 0; i < n2; i++)
arr2[i] = array[mid + 1 + i];
for(k = low, i = 0, j = 0; k <= end; k++){
if(i == n1){
array[k] = arr2[j++];
continue;
}
if(j == n2){
array[k] = arr1[i++];
continue;
}
array[k] = arr1[i] > arr2[j] ? arr1[i++] : arr2[j++];
}
}
void mergesort(int array[], int low, int end){
if(low < end){
int h = (low + end) / 2;
mergesort(array, low, h);
mergesort(array, h + 1, end);
merge(array, low, h, end);
}
}
比较短的
void merge_sort(int *A, int x, int y, int *T){
if(y - x >1){
int m = x + (y - x) /2;
int p = x, q = m, i = x;
merge_sort(A, p, m, T);
merge_sort(A, m, y, T);
while (p < m || q < y){
if(q >= y || (p < m && A[p] <= A[q])) T[i++] = A[p++];
else
T[i++] = A[q++];
}
for(i = x; i < y; i++)
A[i] = T[i];
}
}
快速排序
思想:每次找到一个元素的正确位置,使得左边都比该元素小,右边都比该元素大
性质:平均,最好情况 O(nlog2n) , 最坏情况 O(n2) , 辅助空间 O(1) , 不稳定
int partion(int array[], int a, int b){
int i = a, j = b, key = array[a];
while(i < j){
while(i < j && array[j] > key) j--;
array[i] = array[j];
while(i < j && array[i] < key) i++;
array[j] = array[i];
}
array[i] = key;
}
void Quick(int array[], int low, int end){
if(low < end){
int m = partion(array, low, end);
Quick(array, low, m);
Quick(array, m + 1, end);
}
}
堆排序
思想:利用大顶堆或者小顶堆数据结构,建好堆后,每次把最后面的元素和顶上的元素交换,取出最大(最小)的元素,并调整堆
性质: 三种情况 O(nlog2n) 辅助空间 O(1) , 不稳定
void heapAdjust(int array[], int i, int n){
int l = 2 * i + 1, r = (i + 1) * 2, max = i;
if(l < n && array[l] > array[max])
max = l;
if(r < n && array[r] > array[max])
max = r;
if(max != i){
int tmp = array[max];
array[max] = array[i];
array[i] = tmp;
heapAdjust(array, max, n);
}
}
void heap(int array[], int n){
for(int i = n / 2 - 1; i >= 0; i--)
heapAdjust(array, i, n);
for(int i = n - 1; i > 0; i--){
int tmp = array[0];
array[0] = array[i];
array[i] = tmp;
heapAdjust(array, 0, i);
}
}
shell 排序
思想:用不同的步长将数据划分成组,保持每组之间有序, 不断减小步长,最终使得整个数组有序
性质: 平均、最好情况复杂度 O(nlog2n) , 空间复杂度 O(1) , 不稳定
void shell(int array[], int n){
if(n < 1 || array ==NULL)
return;
for(int d = n /2; d >=1; d /=2){ // 步长改变
for(int i = 0; i <= d; i++){ // 组数
for(int j = i; j < n; j+=d){ // 选择排序
int key = j;
for(int k = j +d ; k < n; k+=d){
if(array[key] > array[k])
key = k;
}
if(key != j){
int tmp = array[key];
array[key] = array[j];
array[j] = tmp;
}
}
}
}
}