【算法】简单排序算法

讲的很简单,因为懒得打字,之后会更新,看不懂可以在评论区问。

源码:https://github.com/lilydedbb/algorithm/blob/master/main.c

这里就从选择排序和插入排序说起,为什么是这两种排序算法,因为效率更高的排序算法一般都是从他们演变改进而来,比如希尔排序,归并排序和应用最多的快排。

选择排序:从第一个元素开始遍历,遍历到某个元素时,从该元素的下一个元素开始,一直到最后一个元素,找到比该元素小且是最小元素的位置,然后交换该元素和这个最小的元素。

插入排序:从第二个元素开始遍历,检查该元素是否比前一个元素小,如果小,则交换位置并且继续比较前前一个元素,知道找到该元素应该在的位置。

选择排序和插入排序的C代码实现:

#include <stdio.h>
void exchange(int *arr, int index1, int index2);
void selectSort(int *arr, int len);
void insertSort(int *arr, int len);

int main() {
    int N;
    int i;
    printf("Input the length of the array: ");
    scanf("%d", &N);
    int arr[N];
    printf("Input the original array: ");
    for(i = 0; i < N; i++){
        scanf("%d", &arr[i]);
    }

    selectSort(arr, N);
    // insertSort(arr, N);
    for(i = 0; i < N; i++){
        printf("%d ", arr[i]);
    }

    return 0;
}

void selectSort(int *arr, int len){
    for(int i = 0; i < len; i++){
        int index = i, min = arr[i];
        for(int j = i + 1; j < len; j++){
            if(arr[j] < min){
                index = j;
                min = arr[j];
            }
        }
        if(index != i)
            exchange(arr, i, index);
    }
}

void insertSort(int *arr, int len){
    for(int i = 1; i < len; i++){
        for(int j = i; j > 0 && arr[j] < arr[j - 1]; j--){
            exchange(arr, j, j - 1);
        }
    }
}

void exchange(int *arr, int index1, int index2){
    int temp = arr[index1];
    arr[index1] = arr[index2];
    arr[index2] = temp;
}

对于长度为N的数组,选择排序需要大约N^2 / 2次比较和N次交换。插入排序最坏情况下需要N^2 / 2次比较和N^2 / 2次交换,最好情况下需要N - 1次比较和0次交换,平均情况下需要N^2 / 4次比较和N^2 / 4次交换。

插入排序在排序部分有序的数组时,表现很优异,而选择排序的效率却不会提高。原因就是插入排序在排序部分有序的数组的时候,会立刻发现其中有序的一部分,不再进行多余的比较和交换,而选择排序则不然,对于任何形式的数组,去论其混乱程度怎样,都需要N^2级的运行时间

希尔排序,就是在插入排序的基础上改进得来的,比插入排序效率更高,但其具体的时间复杂度和空间复杂度的尚不明确,大致为N^(3/2)级时间复杂度。

希尔排序的代码实现:

void shellSort(int *arr, int len){

    int k = 1;
    while(k < len / 3)
        k = k * 3 + 1;

    while(k >= 1){
        for(int i = k; i < len; i++){
            for(int j = i; j - k >= 0 && arr[j] < arr[j - k]; j--){
                exchange(arr, j, j - k);
            }
        }
        k /= 3;
    }
}

归并排序【从基础到高级】

归并排序的基本思想是:把数组分为左右两个小数组,然后分别对左右两个数组排序,然后再通过merge()函数将排序后的左右数组合并起来。

自顶向下和自底向上的归并排序都需要1/2NlgNNlgN次比较,最多访问数组6NlgN次。

其具体实现又分为自顶向下和自底向上两种,代码实现:

// 自顶向下的归并排序
void mergeSort(int *arr, int low, int high){
    if(high <= low)
        return;
    int mid = low + (high - low) / 2;
    mergeSort(arr, low, mid);
    mergeSort(arr, mid + 1, high);
    merge(arr, low, mid, high);
}

// 自底向上的归并排序
void BUMergeSort(int *arr, int len){
    for(int i = 1; i < len; i *= 2){
        for(int j = 0; j < len; j += 2 * i){
            merge(arr, j, j + i - 1, fmin(j + 2 * i - 1, len - 1));
        }
    }
}

// 归并左右数组
void merge(int *arr, int low, int mid, int high){
    int i = low, j = mid + 1, k;
    // 用一个临时数组暂存
    int temp[high + 1];
    for(k = low; k <= high; k++){
        temp[k] = arr[k];
    }
    // 归并
    for(k = low; k <= high; k++){
        if(i > mid)
            arr[k] = temp[j++];
        else if(j > high)
            arr[k] = temp[i++];
        else if(temp[j] < temp[i])
            arr[k] = temp[j++];
        else
            arr[k] = temp[i++];
    }
}

快排是在归并排序的基础上得来的,是一种分治的排序算法,主要思想是,选取数组中的一个数作为基准,然后使基准左边的的数都小于基准,基准右边的数都大于基准,然后再分别对左右数组递归排序【这是简单的二分法快排实现】

// 快速排序
void quickSort(int *arr, int low, int high){
    if(high <= low)
        return;
    int pivot = partition(arr, low, high);
    quickSort(arr, low, pivot - 1);
    quickSort(arr, pivot + 1, high);
}

int partition(int *arr, int low, int high){
    int pivot = arr[low];
    int i = low, j = high + 1;
    while(1){
        while (arr[++i] < pivot)
            if(i == high) break;
        while (arr[--j] > pivot)
            if(j == low) break;
        if(i >= j) break;
        exchange(arr, i, j);
    }
    exchange(arr, j, low);
    return j;
}

二分法实现方式忽略了数组中可能有很多和基准数相同大小的数,没有对这些数作出处理,虽不影响结果的正确性,但是使下一步递归排序的子数组规模不是最小的,即性能上不是最优的。在二分法的基础上,三分法实现方式优化了这一问题。
三分法快排代码实现如下:

// 三向切分的快速排序
void quickSort3way(int *arr, int low, int high){
    if(high <= low)
        return;
    int pleft = low, i = low + 1, pright = high;
    int pivot = arr[low];
    while(i <= pright){
        if(arr[i] < pivot){
            exchange(arr, i++, pleft++);
        }else if (arr[i] > pivot){
            exchange(arr, i, pright--);
        }else{
            i++;
        }
        quickSort3way(arr, low, pleft - 1);
        quickSort3way(arr, pright + 1, high);
    }
}

改进快速排序除了用三向切分实现,还可以综合插入排序优化。

因为对于小数组,快速排序比插入排序慢,所以可以递归到一定程度之后,改用插入排序实现,如:

if(high <= low) 
    return;
// 这两个语句可以改为
if(high <= low + M)
    InsertSort(arr, low, high);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值