常用算法之----选择排序、插入排序和希尔排序

一些说明

我将会写一系列关于算法的博客,因为我是程序员,并不是计算机科学家,也即我是搞工程的,并不是搞学术的,所以对于我来说,最重要的就是

1.有哪些算法

2.这些算法的原理

3.这些算法的实现

4.这些算法的效率

而其他的,相对而言,并没有那么重要,比如算法的证明,所以以后的博客都会按照上述的思维撰写。

一、首先定义一个抽象类,里面集成了排序算法所需要的共同的方法:

public abstract class SortBase {
    public abstract Integer[] sort(Integer[] a);

    public static void print(Integer[] arrayForSort) {
        System.out.print("[");
        for(int i=0;i<arrayForSort.length;i++) {
            if(i == arrayForSort.length - 1) {
                System.out.print(arrayForSort[i]);
            } else {
                System.out.print(arrayForSort[i] + " ,");
            }
        }
        System.out.println("]");
    }

    public static void print(String prefix,Integer[] arrayForSort) {
        System.out.print(prefix + ": ");
        System.out.print("[");
        for(int i=0;i<arrayForSort.length;i++) {
            if(i == arrayForSort.length - 1) {
                System.out.print(arrayForSort[i]);
            } else {
                System.out.print(arrayForSort[i] + " ,");
            }
        }
        System.out.println("]");
    }
}

二、选择排序:

选择排序可以说是最简单的一种排序方法:

1.找到数组中最小的那个元素

2.将最小的这个元素和数组中第一个元素交换位置

3.在剩下的元素中找到最小的的元素,与数组第二个元素交换位置

重复以上步骤,即可以得到有序数组。

代码如下:

public class SelectionSort extends SortBase {

    public Integer[] sort(Integer[] a) {
        print("init",a);
        Integer minIndex = 0;
        Integer temp = 0;
        for(int i=0;i<a.length;i++) {
            minIndex = i;
            for(int j=i+1;j<a.length;j++) {
                if(a[j] < a[minIndex]) {
                    minIndex = j;
                }
            }
            temp = a[i];
            a[i] = a[minIndex];
            a[minIndex] = temp;

            print((i+1) + "",a);
        }
        return a;
    }

    public static void main(String[] args) {
        Integer[] a = {2,1,5,9,0,6,8,7,3};
        print("result",(new SelectionSort()).sort(a));
    }
}

我在代码中打出了每次排序的结果,运行结果如下:

init: [2 ,1 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

1: [0 ,1 ,5 ,9 ,2 ,6 ,8 ,7 ,3]

2: [0 ,1 ,5 ,9 ,2 ,6 ,8 ,7 ,3]

3: [0 ,1 ,2 ,9 ,5 ,6 ,8 ,7 ,3]

4: [0 ,1 ,2 ,3 ,5 ,6 ,8 ,7 ,9]

5: [0 ,1 ,2 ,3 ,5 ,6 ,8 ,7 ,9]

6: [0 ,1 ,2 ,3 ,5 ,6 ,8 ,7 ,9]

7: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

8: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

9: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

result: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

效率:对于长度为N的数组,选择排序需要大约N²/2次比较和N次交换。也即最好、最差、平均时间效率均为O(n²),只需要一个辅助变量帮助交换元素。

选择排序可以看成是冒泡排序的扩展,一个是把最小或最大的选出来,再交换,一个是一直交换直到最大最小的出现在正确的位置上,选择排序相对于冒泡排序,比较次数是一样的,但是交换次数要少很多。

三、插入排序:

插入排序类似整理扑克牌,将每一张牌插到其他已经有序的牌中适当的位置。

插入排序由N-1趟排序组成,对于P=1到N-1趟,插入排序保证从位置0到位置P上的元素为已排序状态。

简单的说,就是插入排序总共需要排序N-1趟,从index为1开始,讲该位置上的元素与之前的元素比较,放入合适的位置,这样循环下来之后,即为有序数组。

代码实现:

public class InsertionSort extends SortBase {

    @Override
    public Integer[] sort(Integer[] a) {
        // TODO Auto-generated method stub
        print("init",a);
        Integer temp = 0;

        for(int i=1;i<a.length;i++) {
            //只能从当前索引往前循环,因为索引前的数组皆为有序的,索引只要确定当前索引的数据的为止即可
            for(int j=i;j>0 && a[j] < a[j-1];j--) {
                temp = a[j];
                a[j] = a[j-1];
                a[j-1] = temp;
            }
            print(i +"",a);
        }

        print("result",a);
        return a;
    }

    public static void main(String[] args) {
        Integer[] a = {2,1,5,9,0,6,8,7,3};
        (new InsertionSort()).sort(a);
    }
}

运行结果:

init: [2 ,1 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

1: [1 ,2 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

2: [1 ,2 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

3: [1 ,2 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

4: [0 ,1 ,2 ,5 ,9 ,6 ,8 ,7 ,3]

5: [0 ,1 ,2 ,5 ,6 ,9 ,8 ,7 ,3]

6: [0 ,1 ,2 ,5 ,6 ,8 ,9 ,7 ,3]

7: [0 ,1 ,2 ,5 ,6 ,7 ,8 ,9 ,3]

8: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

result: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

效率:如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数加上 (n-1)次。平均来说插入排序算法的时间复杂度为O(n^2)

四、希尔排序

把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。

随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。

实现代码:

public class ShellSort extends SortBase {

    @Override
    public Integer[] sort(Integer[] a) {
        // TODO Auto-generated method stub
        print("init",a);
        Integer h = a.length;
        Integer temp = 0;
        while(h >= 1) {
            for(int i=h;i<a.length;i++) {
                for(int j=i;j>=h && a[j] < a[j-h];j -= h) {
                    temp = a[j];
                    a[j] = a[j-h];
                    a[j-h] = temp;

                }
            }
            h /= 9;
        }
        print("result",a);
        return a;
    }

    public static void main(String[] args) {
        Integer[] a = {2,1,5,9,0,6,8,7,3};
        (new ShellSort()).sort(a);
    }
}

运行结果:

init: [2 ,1 ,5 ,9 ,0 ,6 ,8 ,7 ,3]

1: [0 ,1 ,5 ,7 ,2 ,6 ,8 ,9 ,3]

2: [0 ,1 ,2 ,6 ,3 ,7 ,5 ,9 ,8]

3: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

result: [0 ,1 ,2 ,3 ,5 ,6 ,7 ,8 ,9]

效率:

最坏情况时间复杂度为:O(n^1.5),平均时间复杂度为O(nlogn)。

原文地址:https://www.cnblogs.com/xuxinstyle/p/9603681.html

时间: 2024-11-10 08:03:07

常用算法之----选择排序、插入排序和希尔排序的相关文章

算法_基本排序算法之冒泡排序,选择排序,插入排序和希尔排序

排序的元素实现了Comparable接口,以达到对于通用性. 最基础的排序是冒泡排序,下面是其思路: 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. 针对所有的元素重复以上的步骤,除了最后一个. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较. 下面是其实现代码: public class Maopao { public void sort(Comparable[]

选择排序,插入排序以及希尔排序

1. 选择排序 首先,找到数组中最小的那个元素; 将它与数组中的第一个元素交换位置; 在剩下的数组中找到最小的元素,和数组的第二个元素交换位置,如此循环往复; public class Selection{ // 将数组a按升序排列 public static void sort(Comparable[] a){ int N = a.length; for(int i = 0; i < N; i++){ int min = i; for(int j = i + 1; j < N; j++){

七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)

 写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.因此排序掌握各种排序算法非常重要.对下面介绍的各个排序,我们假定所有排序的关键字都是整数.对传入函数的参数默认是已经检查好了的.只是简单的描述各个算法并给出了具体实现代码,并未做其他深究探讨. 基础知识: 由于待排序的记录数量不同,使得排序过程中设计的存储器不同,可将排序方法分为两大类:一类是内部排序,指的是待排序记录存放在计算机随机存储器中进行的排序过程.另一类是外部排序,

数据结构精要------直接插入排序和希尔排序算法

上篇总结中主要实践了算法的内排序的选择排序,那么接下来我们继续实践插入排序排序的两种:直接插入排序和希尔排序算法. -----直接插入排序 package com.sort; /** * 直接插入排序 * * @author weixing-yang * * 算法思路: * 每步将一个待排序的元素,插入到前面已排序好的一组元素中的适当位置, * 直到所有元素全部出入完成为止. */ public class InsertionSort { public void insertionSort(in

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

以下是最近学习各种算法的代码实现: #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(*

直接插入排序、二分插入排序、希尔排序、冒泡排序与简单选择排序

一.直接插入排序 稳定,时间复杂度:最好O(n).最差O(n^2).平均O(n^2),空间复杂度O(1) void InsertSort(int L[], int n) { int i, j,key; for (i = 1; i<n; i++) if(L[i] < L[i-1])//需要将L[i]插入到有序表L[0...i-1] { key = L[i]; for(j = i-1; j >= 0 && key < L[j]; j--)//后移 L[j+1] = L[

【数据结构与算法】内部排序之一:插入排序和希尔排序的N中实现(不断优化,附完整源码)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/20043459   前言 本来想将所有的内部排序总结为一篇博文,但是随着研究的深入,还是放弃了这个念头,斟前酌后,还是觉得分开来写比较好,具体原因,看完本篇博文也就自然明了了. 本篇文章主要探讨插入排序和希尔排序,之所将二者放在一起,很明显,是因为希尔排序是建立在插入排序的基础之上的.     注:以下各排序算法的N种实现方法大部分都是我根据算法思想,自己写出来的,或者是参考其本身的经典实

算法3 七大排序之:直接插入排序和希尔排序

上一篇总结了直接选择排序和堆排序,这一篇要总结的是插入排序中的直接插入排序和希尔排序,我们主要从以下几点进行总结. 1.直接插入排序及算法实现 2.希尔排序及算法实现 3.直接插入排序PK希尔排序 1.直接插入排序及算法实现 什么是直接插入排序呢?直接插入排序的基本思想是:每次从无序序列中取出第一个元素插入到已经排好序的有序序列中,从而得到一个新的,数量加1的有序序列. 1-1.示意图 下面是直接插入排序的图解说明. 1-2.代码 下面是直接插入排序的算法实现代码. InsertSort.jav

Python八大算法的实现,插入排序、希尔排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序、基数排序。

Python八大算法的实现,插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2).是稳定的排序方法.插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素).在第一部分排序完成后,再将这

#排序算法#【2】直接插入排序、希尔排序

直接插入排序法 插入排序的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后移动,为最新元素提供插入空间. 核心代码: //直接插入排序法 void InsertSort(int a[],int n){ int i,j,k,t; for(i = 1 ; i<n;i++){ k = a[i]; /* 第一次比较粗糙的写法 j = i-1; while(