排序复习

基础概念

1: 内部排序:排序算法需要一次性将所有的数据加载到内存中才可以进行排序;
外部排序:排序算法不需要一次性将所有的数据加载到内存中才可以进行排序;(堆排序 归并排序·)
稳定排序:待排序记录中,相同的元素在排序后相对位置保持不变的排序。

插入排序

上代码

void Insert_Sort(int *arr, size_t sz)
{
    for(size_t i = 1; i < sz; ++i)
    {
        int key = arr[i]; // 当前要插入元素
        int end = i - 1; 
        while(key < arr[end] && end >= 0)
        {
            arr[end+1] = arr[end];
            end--;
        }
        arr[end + 1] = key;
    }
} 

需要注意下标 end = i - 1;当前要插入元素需要用key进行保存,避免下标出错,i从1开始,因为arr[0]不需要进行排序。
时间复杂度 : 如果数据的序列与有待排序的序列接近相同,时间复杂度O(n),最差场景这个序列是个逆序,时间复杂度是个O(n^2)。
应用场景:数据接近有序情况下,数据量比较少。
如果数据大量并且并未接近有序,插入排序就需要进行改进为希尔排序

希尔排序

将数据逐步变得有序
在插排基础上对于大量数据进行分组,设置gap值,将数据逐步变得有序。

void Shell_Sort(int *arr, size_t sz)
{
    int gap = 3;
    while(gap > 0)
    {
        for(size_t i = gap; i < sz; ++i)
        {
            int key = arr[i];
            int end = i - gap;
            while(end >= 0 && key <= arr[end])
            {
                arr[end+gap] = arr[end];
                end -= gap;
            }
            arr[end + gap] = key;
        }
        gap--;
    }
}

空间复杂度:O(1) 时间复杂度和gap取值有关
希尔排序是不稳定排序(因为是隔着区间的插入排序)
适用于数据量比较大并且比较凌乱

选择排序

选择排序原理:从所给区间选择出最大或者最小的数据进行放置,每次选择之后都要将区间长度缩短。

void Select_Sort(int* arr,size_t len)
{
    for(size_t i = 0;i < len - 1;++i)
    {
        int min = i;
        for(size_t j = i; j < len;++j)
        {
          if(arr[j] < arr[min])
         {
            min = j;
         }
        }
        Swap(&arr[min],&arr[i]);
    }
}
void Select_Sort(int* arr,size_t len)
{
    for(int i = len - 1; i > 0;--i)
    {
        int max = arr[i];
        for(int j = i; j >= 0;--j)
        {
            if(arr[max] < arr[j])
            {
                max = j;
            }
        }
        Swap(&arr[max],&arr[i]);
    }
}

选择排序有什么缺点呢?
在每次比较的时候并不会记忆比较,造成大量比较重复。
优化可以选择堆排序。

堆排序(也是一种选择排序)

堆排序的关键点
1:找到第一个非叶子节点(也就是最后一个叶子节点的parent)

(size - 2 )  / 2

2: 如何根据parent推算出孩子节点?

lchild = parent * 2 + 1
rchild = parent * 2 + 2 = lchild + 1 

3:如何调整堆?
我认为这个是堆排中最关键的问题,我们在从根节点进行堆调整的时候,向下调整会造成该节点孩子节点的不满足堆的性质,如何使用代码来解决?

		if(array[child] > array[parent])
        {
            Swap(&array[child],&array[parent]);
            parent = child;
            child = parent * 2 + 1;
        }

4:如何保证堆最后的有序性?
利用堆的删除,将堆顶元素和最后一个叶子节点交换,缩小区间,这个思路和选择排序一样,所以说堆排序是选择排序的优化。

来看完整代码:

void HeapAdjust(int array[], int size, int parent)//向下调整
{
    int child = parent * 2 + 1;
    while(child < size)
    {
        //找较大孩子 先保证parent 的右孩子存在

        if(child+1 < size && array[child + 1] > array[child])
        {
            child += 1;
        }

        if(array[child] > array[parent])
        {
            Swap(&array[child],&array[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else 
        {
            return;
        }
    }
}

void HeapSort(int array[], int size)
{
   
    int end = size - 1; 
    for(int root = (size-1)/2;root >= 0;root--)
    {
        HeapAdjust(array,size,root);//向下调整
    }
    //利用堆删除的思想进行排序
    while(end)
    {
        Swap(&array[0] , &array[end]);
        HeapAdjust(array,end,0);
        end--;
    }
}

堆排序空间复杂度 O(1) 时间复杂度 O(Nlog2N) 稳定性: 不稳定

冒泡排序

关键:相邻元素之间的比较

void Bubble_Sort(int *arr,size_t sz)
{
    for(size_t i = 0;i < sz - 1;++i)
    {
        for(size_t j = 0; j < sz - i - 1;++j)
        {
            if(arr[j] > arr[j+1])
            {
               int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

需要注意:防止 j下标越界

j < sz - i - 1

必须要减一,因为比较时arr[j] 和 arr[j+1]进行的比较,i = 0 时会造成 j 数组越界。

时间复杂度: O(N^2)空间复杂度:O(1) 稳定性 : 稳定

快速排序

关键
获取基准值函数:
保证返回的下标左边比基准值小,右边比基准值大
在获取基准值的同时进行交换。

int Pation(int* arr, int left, int right)
{
    int begin = left;
    int end = right-1;
    int key = arr[end];
    while(begin < end)
    {
        while(begin < end && arr[begin] <= key)
        {
            begin++;
        }
        while(begin < end && arr[end] >= key)
        {
            end--;
        }
        if(begin < end)
        {
            Swap(&arr[begin],&arr[end]);
        }
    }
    if(begin != right-1)//begin 不是最后一个元素
    Swap(&arr[begin],&arr[right -1]);
    return begin;
}
void Quick_Sort(int *arr ,size_t left ,size_t right)
{
    if(right - left > 1)
    {
        int div = Pation(arr,left,right); // 基准值
        Quick_Sort(arr,left,div);  
        Quick_Sort(arr,div+1,right);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值