插入排序,希尔排序,堆排序详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了插入排序,希尔排序,堆排序详解相关的知识,希望对你有一定的参考价值。

本文将介绍三种排序算法--插入排序,希尔排序,堆排序。本文所有例子都是使用升序

  一.插入排序

   算法思想

    维护一个有序数组,将要插入的数据与有序数组自最后一个元素直到合适位置的数一一比较。

eg: 有序数组:1,3,5,6,7   现在待插入数据为2,那么他将会和7,6,5,3,依次作比较,当带插入数据小于有序数组最后的元素大小,则将该元素后移,直到待插入元素找到合适位置为止。

   代码实现

void InsertSort(int* a, int size)
02
{
03
    assert(a);
04
    for (int i = 0; i < size - 1; ++i)
05
    {
06
        int end = i;                                 //标识有序数组的最后一位
07
        int tmp = a[end + 1];
08
        while (end >= 0 && tmp < a[end])
09
        {
10
            a[end + 1] = a[end];                     //待插入数据比有序数组的最后一个数小,将有序数组最后一位向后移位
11
            --end;
12
        }
13
        a[end + 1] = tmp;
14
    }
15
}

总结

技术分享    1.插入排序可以认为是间距为1的插入算法,说这个是为了待会儿更好的理解希尔排序。

    2.插入排序的时间复杂度为O(n^2);

    3.插入排序的空间复杂度为O(1);

    4.具有稳定性


 排序算法的稳定性是指,经过排序算法排序的相同元素的相对位置不会发生改变。

  二.希尔排序

   算法思想

    希尔排序可以认为是插入排序的增强版,因为,他加入了一个预排的过程,即在实现间距为1的插入算法之前,他已经预先将间距为gap(gap一直减减直到>0)的数组排列过了。所以,当进行gap = 1的插入排序之前使得待排序数组已经高度接近有序,使得这次进行的gap = 1的排序的时间复杂度,可以小于O(N^2)(gap = 1的插入排序,最好情况的时间复杂度为O(1),前面的预排过程正是出于这个目的)。

   代码实现

//希尔排序
02
void ShellSort(int* a,size_t size)
03
{
04
    assert(a);
05
    int gap = size / 2;
06
    while (gap > 0)
07
    {
08
        for (int i = 0; i < size - gap; ++i)
09
        {
10
            int end = i;                                
11
            int tmp = a[end + gap];
12
            while (end >= 0 && tmp < a[end])
13
            {
14
                a[end + gap] = a[end];                    
15
                end -= gap;
16
            }
17
            a[end + gap] = tmp;
18
        }
19
        --gap;
20
    }
21
}

总结

技术分享 上图为gap = 5 的时候的预排效果图

 1.希尔排序预排的思想和插入排序的思想是一致的,只是,他把原数组分成不同的区间。

 2.希尔排序的时间复杂度为O(N^2),空间复杂度为O(1);

 3,具有不稳定性


 三.堆排序

  算法思想

技术分享代码实现

void AdjustDown(int* a, size_t size, int parent)
02
{
03
    assert(a);
04
    int child = parent * 2 + 1;
05
    while (child<size)
06
    {
07
        if (child+1<size && a[child] < a[child + 1])
08
            ++child;
09
        if (a[parent] < a[child])
10
        {
11
            swap(a[parent], a[child]);
12
            parent = child;
13
            child = parent * 2 + 1;
14
        }
15
        else
16
        {
17
            break;
18
        }
19
         
20
    }
21
}
22
void HeapSort(int* a,size_t size)
23
{
24
    assert(a);
25
    //建堆
26
    for (int i = (size - 2) / 2; i >= 0; --i)  //从第一个非叶子节点开始调
27
    {
28
        AdjustDown(a, size, i);
29
    }
30
    for (size_t i = 0; i < size; ++i)
31
    {
32
        swap(a[0], a[size - 1 - i]);
33
        AdjustDown(a, size - i - 1, 0);
34
    }
35
}

总结


 1.时间复杂度为O(N*lgN),空间复杂度为O(1);


 2.具有不稳定性




 以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。


以上是关于插入排序,希尔排序,堆排序详解的主要内容,如果未能解决你的问题,请参考以下文章

排序算法学习(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序)

七大排序算法(插排,希尔,选择排序,堆排,冒泡,快排,归并)--图文详解

8种面试经典!排序详解--选择,插入,希尔,冒泡,堆排,3种快排,快排非递归,归并,归并非递归,计数(图+C语言代码+时间复杂度)

直接插入排序 ,折半插入排序 ,简单选择排序, 希尔排序 ,冒泡排序 ,快速排序 ,堆排序 ,归并排序的图示以及代码,十分清楚

8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)

8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)