排序算法学习

来源:互联网 发布:猪八戒局域网考试软件 编辑:程序博客网 时间:2024/06/11 22:57

一直都想把排序和搜索类的算法总结一下,一直拖着没写,主要是太懒了,现在决定还是要再好好学习下这些基本的算法。毕竟基础真的是很重要。好了现在开始学习第一个排序算法–插入排序
我记得插入排序在我们以前的数据结构教程上是第一个介绍的^-^

插入排序 听这个排序名字就是将一个什么数要插入到某个地方,不错,他就是将无序数列中的第一个数插入到有序数列中,使得这一组数据都成为有序的。
{3,1,6,4,8,5}
比如这一组无序数据,用插入排序使得有序,首先来看哪一个数值是无序数列中的第一个数字,上面这组数据1就是无序数列中的第一个数字,因为数列中只有一个数字3,不管怎么看都是有序的。这样我们就将1和有序表中的数字进行比较吗,只要比有序表中和无序第一个元素就可以吗,觉得还是比较简单的
于是乎就开始噼噼的写代码了

public static void InsertSort_error(){        int a[] = { 3, 1, 6, 4, 8, 5 };        for (int i = 1; i < a.length; i++) {            if(a[i-1]>a[i]){                int temp = a[i];                a[i] = a[i-1];                a[i-1] = temp;            }        }        for (int i = 0; i < a.length; i++) {            System.out.print(a[i] + ",");        }    }   

写出了上面的这段代码,一运行发现 咦 怎么运行的结果是1,3,4,6,5,8 很明显是错误的,仔细看下上面的代码,发现写成这样把即将要插入的元素有序表里面的最后一个元素进行比较。这里有一个很大的问题就是如果有序表中的倒数第二个元素也比待插入的数据要大的话,就出现了上面的情况啦。好了我们既然知道原因啦,那就要修改下上面的代码了。

要注意的是我们现在要插入的元素是要插入到有序表中的,不是和有序表中的最后一个元素比较就可以了。

public static void InsertSort() {        int a[] = { 3, 1, 6, 4, 8, 5 };        for (int i = 1; i < a.length; i++) {              //key值就是要即将要插入的数值,依次将key值和有序表中的元素比较(逆序比较)              int key = a[i];              int j = i-1;              while(j >= 0 && a[j]>key  ){                  a[j+1] = a[j];                  j--;              }              a[j+1]=key;               }        for (int i = 0; i < a.length; i++) {            System.out.print(a[i] + ",");        }

这次再运行得到的结果是1,3,4,5,6,8,结果是正确的
这段代码就是正确的插入排序,外面的一层循环就是一次遍历无序表中的元素,内层里面的while循环就是将元素正确的插入到有序表中。

上面介绍完了插入排序,再来学习第二个排序算法–选择排序,选择排序的原理就是在一组无序的元素中选择一个最大的或则是最小的数据和第一元素进行交换,使之成为有序数列
{3,1,6,4,8,5}
同样这组数据,使用选择排序,首先是在这组数列中找到最小的元素(这里我们都是用从小到大的顺序进行排序)1,把1和数列中第一个元素的位置进行交换,这样就和3交换,交换之后剩余的就是{3,6,4,8,5},再将这组元素来一次排序,这个次呢3是最小的元素,它也是在数列中的第一个,就不用进行交换了,一次类推,当无序数列中的元素为0的时候,这个时候排序就完成了啦
下面就是选择排序的代码实现

// {3,1,6,4,8,5}    public static void selectSort() {        int a[] = { 3, 1, 6, 4, 8, 5 };        for (int i = 0; i < a.length; i++) {            int pos = i;            for (int j = i + 1; j < a.length; j++) {                if (a[pos] > a[j]) {                    //pos 就是指想最想元素的下标                    pos = j;                }            }            //这里进行判断当要交换的元素本身就是第一个的话,那就不用交换了            if(pos != i){                int temp = a[i];                a[i] = a[pos];                a[pos] = temp;            }        }    }

接下来就开始介绍冒泡排序了,冒泡排序的原理是不断的遍历数列,比较相邻的两个元素,如果这两个元素排序不正确,就把他们交换过来,直到没有交换,就说明排序已经完成了
{3,1,6,4,8,5}
同样进行一次遍历,还是按照从小到大来进行排序,一次遍历之后会出现1,3,4,6,5,8,再进行下一次遍历,直到整个没有交换,就说明已经完成排序了

public static void bubbleSort(){        int a[] = { 3, 1, 6, 4, 8, 5 };         while(true){            boolean flag = true;            for(int i = 0; i< a.length-1 ;i++){                             if(a[i]>a[i+1]){                    flag = false;                    int temp = a[i];                    a[i] =a[i+1];                    a[i+1] = temp;                }            }            //如果没有交换了,说明排序已经完成了            if(flag){                break;            }        }

下面一个排序就是快速排序,快速排序的原理就是将一组待排数列,以一个元素为基准点,分成两部分,使得一部分的所有数据比另一部分的所有数据都要小,再分别将这两组数据进行快排,直到数列有序
{3,1,6,4,8,5}
上面的这组数列,我们以3为基准值,来进行一次快排,比3小的在他的左边,比3大的在右边。进行一次快速排序之后 {1,3,6,4,8,5}
那么快速排序用代码要怎样实现
{3,1,6,4,8,5}
我们先定义两个索引下标,begin,end分别对应着数组第一个元素和最后一个元素,首先以3为基准值,从后往前看如果发现有比基准值3小的数字,就将它与三进行交换,此时的i++;再从i+1的位置从前往后比较,如果发现有比基准值大的数值就将他复制给刚刚j值(注意这个j值是递减的,下标j值对应的应该是刚刚进行从后往前遍历时比基准值要小的小标)这样依次比较,知道i>=j,这一轮的快排就可以将数列分成以3为基准值得两部分。
下面就是我们的代码实现

public static void quickSort(int[] a,int begin ,int end){        //{3, 1, 6, 4, 8, 5}        //基准值        int refer = a[begin];        int i = begin;        int j = end;        while(i<j){            while(a[j] > refer && i < j){                j--;                            }            System.out.println(j);            //从后往前遍历,出现比基准值要小的数则将它和基准值交换            if(i<j){                a[i] = a[j];                i++;            }            //从前往后遍历,返现比基准值要大的数,则将它放到从后往前遍历,比基准值小的数的位置            while(a[i]< refer && i < j){                i++;            }            if(i<j){                a[j] = a[i];                j--;            }        }        a[i] = refer;               if(begin < (i-1)){            quickSort(a, begin, i-1);        }        if((j+1)<end){            quickSort(a, j+1, end);        }       } 

说完上面的快速排序之后,接下来要看得是希尔排序,希尔排序是一个高效版的插入排序。希尔排序是把记录按下标的一定增量分组,对每组使用插入排序算法排序;随着增量逐渐减少,当增量减至1时,整个文件恰被分成一组,排序就完成了。
{33, 13, 64, 45, 18, 15,56,32,54}
这里的增量值就是取数组长度/2,即为4,经过一个分组排序后,增量值/2,直到增量值为1.
33, 13, 64, 45, 18, 15,56,32,54
下标 0 1 2 3 4 5 6 7 8
第一组 33 18 54
第二组 13 15
第三组 64 56
第四组 45 32
分别对着四组数据进行插入排序,再进行第二轮插入排序的时候这时的增量就为2了
来看下第一次分组排序完成后这些数据
18,13,56,32,33,15,64,45,54
以增量为2再进行分组排序
18, 13, 56, 32, 33, 15,64,45,54
下标 0 1 2 3 4 5 6 7 8
第一组 18 56 33 64 54
第二组 13 32 15 45
下面是排序结果
18,13,33,15,54,32,56,45,64,
以增量为1进行分组排序,就是第一个介绍的插入排序啦
下面是排序结果
13,15,18,32,33,45,54,56,64
下面通过代码来实现下

//希尔排序,将待排数据按照增量分成几组,在分别对着几组数据进行插入排序    //随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,排序完成    public static void shellSort(){        int a[] = {33, 13, 64, 45, 18, 15,56,32,54};        int d = a.length;        while(true){            d = d/2;            System.out.println(d);            for(int i = 0 ;i < d ;i++){                //分别对每组元素进行插入排序                for(int j = i+d ; j<a.length; j+=d){                    int key = a[j];                    int k = j - d;                    while (k >= 0 && a[k] > key) {                        a[k + d] = a[k];                        k = k -d;                    }                    a[k + d] = key;                }            }            if(1 == d){                break;            }        }           for (int i = 0; i < a.length; i++) {            System.out.print(a[i] + ",");        }    }
0 0
原创粉丝点击