常用排序算法

写这个博客的主要是因为总是感觉自己的算法学的不够扎实,所以打算写下来加强自己的理解。

这里写图片描述

图片来自这


插入排序

思想:在一个已经有序的小序列基础上,一次插入一个元素。

性质: 平均最坏情况都是 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;
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值