排序算法

稳定性:排序之后,相同排序码一样的和排序之前顺序一样。

#include <stdio.h>
#include <stdint.h>

/
//冒泡排序
//时间复杂度:O(N ^ 2)
//空间复杂度:O(1)
//稳定性:稳定排序


void Swap(int* a, int* b){
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
    return;
}

//升序
void BubbleSort(int array[], size_t size){
    if(size < 1){
        return;
    }
    //[0,bound) 表示有序元素
    //[bound, size)表示一个待排序空间
    size_t bound = 0;
    for(;bound < size; ++bound){
       size_t cur = size - 1; 
       for(; cur > bound; --cur){
           if(array[cur] < array[cur - 1]){
               Swap(&array[cur], &array[cur - 1]);
           }
       }
    }
    return;
}

/
//选择排序
//时间复杂度:O(N ^ 2)
//空间复杂度:O(1)
//稳定性:不稳定排序


void SelectSort(int array[], size_t size){
    if(size <= 1){
        return;
    }
    //[0,bound) 表示有序元素
    //[bound, size)表示一个待排序空间
    size_t bound = 0;
    for(; bound < size; bound++){
        size_t cur = bound + 1;
        for(; cur < size; ++cur){
            if(array[bound] > array[cur]){
                Swap(&array[bound], &array[cur]);
            }
        }
    }
    return;
}

/
//插入排序
//时间复杂度:O(N ^ 2)
//空间复杂度:O(1)
//稳定性:稳定排序
//特点:
// 1.数组元素个数比较小,执行效率比较快
// 2.如果数组基本有序,执行效率也很快


//把有序区间当做线性表,把当前bound指向的元素插入到有序区间这个线性表中
//1.定义好边界
//2.保存bound指向的元素
//3.从后往前去找一个合适的位置,一边找一边搬运

void InsertSort(int array[], size_t size){
    if(size <= 1){
        return;
    }
    //[0,bound) 表示有序元素
    //[bound, size)表示一个待排序空间
    //有序区间当成线性表
    size_t bound = 1;
    for(;bound < size; bound++){
        //保存意义是为了后面搬运
        //保存之后,array[bound]值就可以修改
        int bound_value = array[bound];
        //cur辅助我们搬运下标
        //从后往前遍历,找合适的位置放置 bound_value
        size_t cur = bound;
        for(;cur > 0; --cur){
            if(array[cur - 1] > bound_value){
                //进行搬运
                array[cur] = array[cur - 1];
            }else{
                //说明已经找到合适位置
                break;
            }
        }
        array[cur] = bound_value;
    }
    return;
}

/
//堆排序
//时间复杂度:O(N * logN)
//空间复杂度:O(1)
//稳定性:不稳定排序


//堆的性质:
//1.完全二叉树
//2.如果是小堆,父节点的值小于子节点, 如果是大堆,父节点的值大于子节点的
//
//如果要实现升序排序,就要使用大堆
//
//步骤:
//1.基于数组建立一个堆;(如果升序,建立大堆)
//2.循环删除堆顶元素,删除完毕,排序完成

//方法一:
//把新元素放到素组末尾,上浮式调整(从前往后遍历)
//方法二:
//采用下沉式的调整。(从前往后遍历,起始位置就是堆从后往前遍历的第一个非叶
//子节点,找到其父节点,将其父节点和子节点比较决定是否调整)

void AdjustUp(int array[], size_t size, size_t index){
    (void)size;
    size_t child = index;
    size_t parent = (child - 1) / 2;
    while(child > 0){
        if(array[parent] < array[child]){
            Swap(&array[parent], &array[child]);
        }else{
            break;
        }
        child = parent;
        parent = (child - 1) / 2;
    }
}

void AdjustDown(int array[], size_t size, size_t index){
    size_t parent = index;
    size_t child = 2 * parent + 1;
    while(child < size){
        //我们要升序排序,需要建立大堆
        if(child + 1 < size && array[child + 1] > array[child]){
            child = child + 1;
        }
        if(array[child] > array[parent]){
            Swap(&array[parent], &array[child]);
        }
        parent = child;
        child = 2 * parent + 1;
    }
}

void HeapCreate(int array[], size_t size){
    if(size <= 1){
        return;
    }
#if 1
    size_t i = (size - 1 - 1) / 2;
    for(; i > 0; --i){
        AdjustDown(array, size, i);
    }
    AdjustDown(array, size, 0);
#else
    //上浮式调整
    //[0,bound)表示堆的有效区间
    size_t bound = 0;
    for(; bound <size; ++bound){
        AdjustUp(array, bound + 1, bound);
    }
#endif
}

//heap_size 表示当前数组中的哪部分元素是堆

void HeapPop(int array[], size_t heap_size){
    if(heap_size <= 1){
        return;
    }
    Swap(&array[0], &array[heap_size - 1]);
    AdjustDown(array, heap_size - 1, 0);
}

void HeapSort(int array[], size_t size){
    if(size <= 1){
        return;
    }
//1.基于数组建立一个堆;(如果升序,建立大堆)
    HeapCreate(array,size);
//2.循环删除堆顶元素,删除完毕,排序完成
    size_t i = 0;
    for(; i < size - 1; i++){
        //第二个参数表示数组中哪部分区间符合堆的规则
        //第一次删除之前,[0,size)都是堆
        //第二次删除之前,[0, size -1) 都是堆
        HeapPop(array, size - i);
    }
    return;
}

/
//希尔排序
//时间复杂度:取决于步长序列,对于希尔排序,O(N ^ 2)
//如果选择一个最优序列,时间复杂度最高可达(1.3 ^ N)
//空间复杂度:O(1)
//稳定性:不稳定排序


//插入排序的改进版本
//分组式的插入排序
//假设步长是3  70 30 40 10 80 20 90 100 75 60
//第一组:70 10 90 60      10 60 70 90
//第二组:30 80 100        30 80 100
//第三组:40 20 75         20 40 75
//排序后:10 30 20 60 80 40 70 100 75 90

//假设步长为2
//第一组:10 20 80 70 75    10 20 70 75 80
//第二组:30 60 40 100 90   30 40 60 90 100
//排序后:10 30 20 40 70 60 75 90 80 100

//假设步长为1
//10 30 20 40 70 60 75 90 80 100
//排序后:10 20 30 40 60 70 75 80 90 100
//步长常选择: N/4, N/4, N/8, ...., 1

void ShellSort(int array[], int64_t size){
    if(size <= 1){
        return;
    }
    //此时我们使用希尔序列
    //此循环相当于先处理第一组的第一个数据,第二组的第一个数据,第三组第一个元素 第一组第二个元素......
    int64_t gap = size / 2;
    for(; gap > 0; gap /= 2){
        //第二重循环,进行插入排序
        int64_t bound = gap;// 此处相当于插入排序中的bound = 1
        for(; bound < size; ++bound){
            int bound_value = array[bound];
            //第三重循环,线性表的查找和搬运
            int64_t cur = bound;
            //此处cur -= gap 就是找到同组元素的上一个元素
            for(; cur >= gap; cur -= gap){
                if(array[cur - gap] > bound_value){
                    //进行搬运
                    array[cur] = array[cur - gap];
                }else{
                    //说明找到了
                    break;
                }
            }
            array[cur] = bound_value;
        }
    }
}


/
//归并排序
//时间复杂度:O(N ^ 2)
//空间复杂度:O(1)
//稳定性:不稳定排序

void _MergeSort(int array[], int64_t beg, int64_t end, int* tmp){
    if(end - beg <= 1){
        //要么一个元素,要么没有元素,要么非法区间
        return;
    }
    int64_t mid = beg +(end - beg) / 2;
    //此时有了两个区间[beg, mid), [mid, end)
    _MergeSort(array, beg, mid, tmp);
    _MergeSort(array, mid, end, tmp);
    _MergeArray(array, beg, mid, end, tmp);
    return;
}

void MergeSort(int array[], size_t size){
    int* tmp = (int*)malloc(sizeof(int) * size); 
    _MergeSort(array, 0, size, tmp);
    if(size <= 1){
        return;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值