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

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

一.插入排序

算法思想

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

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.具有不稳定性

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

时间: 2024-10-29 19:05:35

插入排序,希尔排序,堆排序详解的相关文章

插入排序 | 冒泡排序 | 希尔排序 | 堆排序 | 快速排序 | 选择排序 | 归并排序

以下是最近学习各种算法的代码实现: #include <stdlib.h> #include <stdio.h> #include <time.h> #include <limits.h> typedef int EleType; typedef int (*CompFunc)(void *,void *); int IntComp(void * a,void *b) { if(*(int *)a > *(int *)b) return 1; if(*

Java各种排序算法详解

排序大的分类可以分为两种:内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.下面讲的排序都是属于内排序. 内排序有可以分为以下几类: (1).插入排序:直接插入排序.二分法插入排序.希尔排序. (2).选择排序:简单选择排序.堆排序. (3).交换排序:冒泡排序.快速排序. (4).归并排序 (5).基数排序 一.插入排序 ?思想:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置,直到全部插入排序完为止. ?关键问

基本排序之详解归并排序

归并排序 一.归并排序的效率是仅次于快速排序的稳定的排序算法,其时间复杂度为O(nlog2n).我们对n 个元素进行一次归并排序时,归并的次数约为log2n,每一次的两路归并排序元素的比较次数约为n-1. 二.归并排序的基本思想: 归并排序是通过将一列数组序列中的元素看成一个一个的小序列来进行归并,直到所有的元素都被归并完成后,排序即完成,便是成功的完成了排序操作. 三.原理: 如:我们对n 为9吧,这样更加好,如,a[9] = {1,2,5,4,3,8,6,7,9}这样的一个数组: 原数组:

插入排序) 希尔排序 (最小增量排序)

/** * (插入排序) 希尔排序 (最小增量排序) * @author Cinn * */public class shellSort { /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        int[] array= {48,58,50,98,69,51,27,99,100};        shlees

设计模式 - 模板方法模式(template method pattern) 排序(sort) 详解

模板方法模式(template method pattern) 排序(sort) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式的一个主要的应用是排序(sort)算法. 对象的排列方式并不是完全相同, 所以需要排序(sort)算法compareTo()

必须知道的八大种排序算法【java实现】(二) 选择排序,插入排序,希尔算法【详解】

一.选择排序 1.基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换:然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止. 2.实例 3.算法实现 /** * 选择排序算法 * 在未排序序列中找到最小元素,存放到排序序列的起始位置 * 再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾. * 以此类推,直到所有元素均排序完毕. * @param numbers */ public static void selectSort(in

常见排序算法详解(冒泡、选择、插入、快速、希尔、归并)

一.排序算法 1.冒泡排序(Bubble Sort) 定义:是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端. 原理: 比较相邻的元素.如果第一个比第二个大(升序),就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数. 针对所有的元素重复以上的

排序算法详解(Go语言实现):冒泡排序/选择排序/快速排序/插入排序

算法是程序的灵魂,而排序算法则是一种最基本的算法.排序算法有许多种,本文介绍4中排序算法:冒泡排序,选择排序,快速排序和插入排序,以从小到大为例. 一.冒泡排序 冒泡排序的原理是,对给定的数组进行多次遍历,每次均比较相邻的两个数,如果前一个比后一个大,则交换这两个数.经过第一次遍历之后,最大的数就在最右侧了:第二次遍历之后,第二大的数就在右数第二个位置了:以此类推. //冒泡排序(排序10000个随机整数,用时约145ms) func bubbleSort(nums []int) { for i

13种排序算法详解

0.前言 从这一部分开始直接切入我们计算机互联网笔试面试中的重头戏算法了,初始的想法是找一条主线,比如数据结构或者解题思路方法,将博主见过做过整理过的算法题逐个分析一遍(博主当年自己学算法就是用这种比较笨的刷题学的,囧),不过又想了想,算法这东西,博主自己学的过程中一直深感,基础还是非常重要的,很多难题是基础类数据结构和题目的思想综合发散而来.比如说作为最基本的排序算法就种类很多,而事实上笔试面试过程中发现掌握的程度很一般,有很多题目,包括很多算法难题,其母题或者基本思想就是基于这些经典算法的,