简单排序算法 冒泡排序 选择排序 插入排序

冒泡排序:

  总体思路:对未排序的各个元素,依次比较两个元素,如果这两个元素为逆序(与想要的顺序相反),则交换这两个元素。

这样可以有两种排序的思路:

思路一:

  固定位置排序:比如有一个未排序队列,下标依次为0,1,2,.....N-1,

      第一轮排序:首先固定位置0,将下标为0的元素依次和下标为1、下标为2、....下标为N-1的元素相比较,若相比较的两个元素为逆序,则交换这两个元素,这样第一轮排序完之后,位置为0的元素,就是最大的(最小的)。

  第二轮排序:首先固定位置1,将下标为1的元素依次和下标为2、下标为3、....下标为N-1的元素相比较,若相比较的两个元素为逆序,则交换这两个元素,这样第二轮排序完之后,位置为1的元素,就是第二大的(第二小的)。

     ...

  第i轮排序(i<N-1):首先固定位置i,将下标为i的元素依次和下标为i+1、下标为i+2、....下标为N-1的元素相比较,若相比较的两个元素为逆序,则交换这两个元素,这样第i轮排序完之后,位置为i的元素,就是第i+1大的(第i+1小的)。

  第N-1轮排序:首先固定位置N-2,将下标为N-2的元素和下标为N-1的元素相比较,若相比较的两个元素为逆序,则交换这两个元素,这样第N-1轮排序完之后,位置为N-2的元素,就是第N-1大的(第N-1小的)。

     这样经过N-1轮排序之后,各个位置的元素都是已经排好序了的。

     固定位置排序代码演示如下:

  

import java.util.Arrays;
public class BubboleSort {
    public static void main(String[] args) {
        BubboleSort bs = new BubboleSort();
        int[] array = {2,5,1,3,9,8,0,4,6};
        System.out.println(Arrays.toString(array));
        bs.bubbleSort(array);
        System.out.println(Arrays.toString(array));
    }

    public void bubbleSort(int[] array){
        //外层取出一个用来比较的位置,当位置i确定之后,内层循环进行完之后,该位置的元素就确定了
        for (int i = 0; i < array.length; i++) {
            //内层循环依次取出需要进行比较的数据
            for (int j = i+1; j < array.length; j++) {
                if (array[i] > array[j]) {
                    swap(array,i,j);
                }
            }
        }
    }
   //交换数组中位置i和位置j的元素
    public void swap(int[] array,int i,int j){
        array[i] = array[i]^array[j];
        array[j] = array[i]^array[j];
        array[i] = array[i]^array[j];
    }
}

控制台输出:

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

思路二:

  相邻元素比较:将相邻的两个元素依次进行比较,如果这两个元素逆序,则进行交换。比如有一个未排序队列,下标依次为0,1,2,.....N-1,

  第一轮排序:

    将下标为0的元素和下标为1的元素进行比较,若逆序,则交换;

       再将下标为1的元素和下标为2的元素进行比较,若逆序,则交换;

    再将下标为2的元素和下标为3的元素进行比较,若逆序,则交换;

    ...

    将下标为i(i<N-2)的元素和下标为i+1的元素进行比较,若逆序,则交换;

    最后将下标为N-2的元素和下标为N-1的元素进行比较,若逆序,则交换。

  这样,经过第一轮排序之后,最大(最小)的元素,就排在最后面了(下标为N-1),即队列最后的元素是排好序的,下一轮排序不用再排序了。

    第二轮排序:

    将下标为0的元素和下标为1的元素进行比较,若逆序,则交换;

       再将下标为1的元素和下标为2的元素进行比较,若逆序,则交换;

    再将下标为2的元素和下标为3的元素进行比较,若逆序,则交换;

    ...

    将下标为i(i<N-3)的元素和下标为i+1的元素进行比较,若逆序,则交换;

    最后将下标为N-3的元素和下标为N-2的元素进行比较,若逆序,则交换。

  这样,经过第二轮排序之后,最二大(最二小)的元素,就排在最后面了(下标为N-2),即下标为N-2的元素是排好序的,下一轮排序不用再排序了。

     重复上面的排序思路即可将剩余的元素全部排好顺序。

代码演示如下:

import java.util.Arrays;
public class BubboleSort {
    public static void main(String[] args) {
        BubboleSort bs = new BubboleSort();
        int[] array = {2,5,1,3,9,8,0,4,6};
        System.out.println(Arrays.toString(array));
        bs.bubbleSort(array);
        System.out.println(Arrays.toString(array));

    }
    //相邻元素进行比较排序
    public void bubbleSort(int[] array){
        //i用来控制比较的次数
        for (int i = array.length -1; i > 0 ; i--) {
            //内层循环完成之后,表示一轮冒泡完成
            for (int j = 0; j < i; j++) {
                if (array[j] > array[j+1]) {
                    swap(array,j,j+1);
                }
            }
        }
    }
    //交换数组中位置i和位置j的元素
    public void swap(int[] array,int i,int j){
        array[i] = array[i]^array[j];
        array[j] = array[i]^array[j];
        array[i] = array[i]^array[j];
    }
   
}

 控制台输出:

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

冒泡排序性能:比较和交换的次数为 O(n2)

 

选择排序:

  假设有一个待排序的数组array,下标依次为0,1,2,3,....N-1

  第一轮排序:从所有元素中选择一个最小(最大)值array[i],放在array[0]位置(即让array[i]与array[0]交换)。

  第二轮排序:从array[1]开始,找出一个最小(最大)值array[j],放在array[1]位置。

  ...

  N个数,要进行N-1轮排序。

  下面是代码演示:

import java.util.Arrays;

public class SelectSort {
    public static void main(String[] args) {
        SelectSort ss = new SelectSort();
        int[] array = {2,5,1,3,9,8,0,4,6};
        System.out.println(Arrays.toString(array));
        ss.selectSort(array);
        System.out.println(Arrays.toString(array));
    }
    public void selectSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i+1; j < array.length; j++) {
                //只记录位置,暂时不交换
                if (array[minIndex] > array[j]) {
                    minIndex = j;
                }
            }
            //经过内层循环之后,找到了该轮外层循环的位置i的要交换的最小值的位置minIndex,交换,若i== minIndex,说明位置i所在的元素,就是该轮比较的最小值了,所以不用交换了
            if (i != minIndex) {
                swap(array,i,minIndex);
            }
        }
    }

    public void swap(int[] array,int i,int j){
        array[i] = array[i]^array[j];
        array[j] = array[i]^array[j];
        array[i] = array[i]^array[j];
    }
}

控制台输出:

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

选择排序效率:比较次数为O(n²),交换的次数为O(n)

 插入法排序:

基本思路:(设数组为升序) 每拿到一个元素,都要将这个元素依次与它之前的元素进行比较,若前面的元素比该元素大,则将前面的元素往后移动;直到前面的元素(设下标为i)比该元素小,则下标为i+1,就是该元素要插入的位置,插入即可
代码演示如下:
package com.lewis.sort.simpleSort;


import java.util.Arrays;

public class InsertSort {
    public static void main(String[] args) {
        InsertSort is = new InsertSort();
        int[] array = {2, 5, 1, 3, 0,9,-1, 8, 7, 4, 6};
        System.out.println(Arrays.toString(array));
        is.sort(array);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 插入法排序:通过构建有序数列,将未排序的元素,从后往前依次比较,进而找到要插入的位置并插入
     * @param array
     */
    public void sort(int[] array){
        int j = 0;
        //假设数组中的第一个元素是已经排好序的
        //外层循环 表示待排序的元素
        for (int i = 1; i < array.length; i++) {
            //待排序的元素tmpData,要找到一个合适的位置插入
            int tmpData = array[i];
            //内层循环从待排序元素tmpData开始,依次往前扫描
            for (j = i; j > 0 ; j--) {
                //将待排序元素tmpData依次和前面的元素比较, 若前面的元素比待排序的元素tmpData大,则将前面的元素依次往后移动
                if (array[j - 1] > tmpData) {
                    array[j] = array[j-1];
                }
                else{
                    //说明前面已经是排好顺序了
                    break;
                }
            }
            //内层循环结束之后,位置j就是待排序元素要插入的位置
            array[j] = tmpData;
        }
    }

}

控制台输出:

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

插入法排序效率:比较和交换次数都为 O(n²),但是比冒泡算法大约快一倍左右,比选择排序稍快,尤其是部分数据局部有序的情况下,插入法排序效率会更高

posted @ 2016-01-13 14:32 路易小七 阅读(...) 评论(...) 编辑 收藏