插入排序和选择排序

排序:将一组杂乱无章的数据按照一定的规则有组织地排列起来。
排序的稳定性:如果在排序中,存在前后相同的两个元素的话,排序前和排序后他们的相对位置不发生变化。

今天,先来学习插入排序和选择排序:
这里写图片描述
插入排序
直接插入排序
(1)思想:

每一步将一个待排序的元其排序码的大小,插入到前面已将排好序的一组元素的合适位置上去,直到全部元素插入完为止。
元素集合越接近有序,直接插入排序算法的时间效率越高。

(2)复杂度

最优:时间效率O(n) 已经有序,只需要比较n-1
最差:时间复杂度O(n^2)
数组全部为逆序,一共需要比较(n-1)+(n-2)+…+1,是一个等差数列
空间复杂度:O(1),它是一种稳定的排序算法。

(3)优缺点:

优点:元素很少的时候,效率很高
缺点:元素很多的时候,需要挪动很多数据,逆序或者接近逆序的情况下效率很差。

(4)图解:
这里写图片描述
(5)代码实现:

void Print(int *a,size_t n)
{
    assert(a);
    for(size_t i = 0;i<n;i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;
}
void InsertSort(int* a,size_t n)
{
    assert(a);
    for(size_t i =1;i<n;i++)
    {
        int end = i-1;
        int tmp = a[i];
        while(end>=0)
        {
            if(tmp>=a[end])
                break;
            a[end+1] = a[end];
            end--;
        }
        a[end+1] = tmp;
    }
}
int main()
{
    int a[8]= {6,1,0,5,2,9,7,3};
    int len = sizeof(a)/sizeof(a[0]);
    InsertSort(a,len);
    Print(a,len);
}

希尔排序
是对直接插入排序的一种优化,在直接插入排序之前进行预排序,将较小的元素快速地放到前面。
(1)思想:

先把元素进行分组,每一组的每一个元素之间的间隙相等 ,对这些组分别进行直接插入排序. 将间隙缩小,重复上步骤,直到间隙值为1时,进行最后一趟直接插入排序。

(2)复杂度:

在逆序或者接近逆序的情况下比插入排序的效率高。
O(n)< 希尔排序的时间复杂度 < O(n*n)
空间复杂度:O(1) 占用有限的数组空间

(3)优缺点

优点:解决了直接插入排序在元素较多,接近逆序情况下需要挪动很多数据的缺陷。
缺点:在元素很多的时候,快速排序效率更高。

(4)图解:
这里写图片描述

(5)代码实现:

void ShellSort(int* a,size_t n)
{
    assert(a);
    size_t gap = n;
    while(gap > 1)//while循环控制着多次循环
    {
        //该公式可以保证最后一趟排序的gap为1
        gap = gap/3 + 1;
        int end=n;
        for(size_t i = 0;i<end-gap;i++)
        {
            int end = i;
            int tmp = a[end+gap];//每组差值为gap
            while(end >= 0 && a[end]>tmp)
            {
                if(tmp>=a[end])
                    break;
                a[end+gap] = a[end];
                end -= gap;
            }
            a[end+gap] = tmp;//进行插入
        }
    }
}
int main()
{
    int a[9]= {9,8,7,6,5,4,3,2,1};
    int len = sizeof(a)/sizeof(a[0]);
    ShellSort(a,len);
    Print(a,len);
}

选择排序
选择排序
(1)思想:

选择出当前范围内的最小值;将该最小值放入当前范围的第一个位置;缩小排序的范围,直到只有范围中只有一个元素为止。

(2)复杂度

时间复杂度:O(n*n) 每趟排序比较的次数是一个等差数列,是一种不稳定的排序算法
空间复杂度: O(1)

(3)图解:
这里写图片描述
(4)代码实现

void Print(int *a,size_t n)
{
    assert(a);
    for(size_t i = 0;i<n;i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;
}
void SelectSort(int* arr,size_t len)
{
    assert(arr>0);
    assert(len>0);
    for(int i = 0;i < len -1;i++)
    {
        for(int j = i+1;j<len;j++)
        {
            if(arr[j]<arr[i])
            {
                swap(arr[i],arr[j]);
            }
        }
    }
}
int main()
{
    int a[8]= {6,1,0,5,2,9,7,3};
    int len = sizeof(a)/sizeof(a[0]);
    SelectSort(a,len);
    Print(a,len);
}

堆排序
堆创建:升序——>建大堆 降序——>建小堆
是一种处理大批量数据排序的算法,使用了大堆(或小堆)的关键字最大(或最小)的特征,建立堆进行排序,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

(1)思想:

首先根据元素建堆,然后将堆的根节点取出(将根节点与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有的节点都取出。

(2)复杂度:

堆排序单趟排序的时间复杂度为O(logN),需要排N次,所以堆排序的时间复杂度为O(N*logN)
空间复杂度O(1)
堆排序是一种不稳定的排序算法

(3)优缺点

优点:排序比较快
缺点:堆排序只能排序存储于数组中的元素,故在某些场合无法使用。

(4)代码实现:

void AdjustDown(int* a, size_t n, size_t i)  
{  
    int parent = i;  
    int child = parent * 2 + 1;  
    while (child < n)  
    {  
        //找出孩子的最大值  
        if (child + 1 < n && a[child+1] > a[child])  
            child++;  

        if (a[child]>a[parent])  
        {  
            swap(a[child], a[parent]);  
            parent = child;  
            child = child * 2 + 1;  
        }  
        else  
        {  
            break;  
        }  
    }  
} 
void HeapSort(int* a,size_t n)  
{  
    //构建一个堆  
    int* heap = new int[n];  

    for (size_t i = 0; i < n; i++)  
    {  
        heap[i] = a[i];  
    }  
    //向下调整  
    for (int i = (n-2)/2; i >= 0; --i)  
    {  
        AdjustDown(heap, n, i);  
    }  

    //堆排序的实质性部分  
    int end = n - 1;  
    //先将第一个元素和最后一个元素的值进行交换  
    //然后将最后一个元素不再视为堆内的内容,缩小排序范围  
    while (end>0)  
    {  
        swap(heap[0], heap[end]);         
        AdjustDown(heap, end, 0);  
        end--;   
        }                                           
        //打印  
        for (size_t i = 0; i < 10; i++)  
        {  
            cout << heap[i] << " ";  
        }  
        cout << endl;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值