简单排序算法 冒泡排序 选择排序 插入排序
冒泡排序:
总体思路:对未排序的各个元素,依次比较两个元素,如果这两个元素为逆序(与想要的顺序相反),则交换这两个元素。
这样可以有两种排序的思路:
思路一:
固定位置排序:比如有一个未排序队列,下标依次为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²),但是比冒泡算法大约快一倍左右,比选择排序稍快,尤其是部分数据局部有序的情况下,插入法排序效率会更高