Java实现八大排序算法

选择排序:

/**
 * 选择排序
 * 原理:遍历一遍找到最小的,与第一个位置的数进行交换。然后在剩下的数当中再找最小的与第二个位置的数交换...
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4]
 * 第一遍:[2, 9, 4, 7, 12, 8, 3, 4]
 * 第二遍:[2, 3, 4, 7, 12, 8, 9, 4]
 * 第三遍:[2, 3, 4, 7, 12, 8, 9, 4]
 * 第四遍:[2, 3, 4, 4, 12, 8, 9, 7]
 * 第五遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第六遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第七遍:[2, 3, 4, 4, 7, 8, 9, 12]
* 紫色代表上一轮排好序的数组,红色代表本轮最小元素
*
* 最好:O(n^2) 最坏:O(n^2) 平均:O(n^2)
*/ public class SelectSort { public static void selectSort(int[] array) { int temp;// 将剩余数组最小的数和当前数交换的变量 int min;// 定义的索引下标变量 for (int i = 0; i < array.length - 1; i++) { min = i; for (int j = i + 1; j < array.length; j++) { if (array[min] > array[j]) { min = j; } } temp = array[min]; array[min] = array[i]; array[i] = temp; } } }

冒泡排序:

/**
 * 冒泡排序
 * 原理:循环n-1次,每次比较两个元素,第一趟比完将最大的元素在最后面,第二趟比较剩余元素,剩余最大元素在倒数第二位,依此类推。
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4]
 * 第一遍:[2, 4, 7, 9, 8, 3, 4, 12]
 * 第二遍:[2, 4, 7, 8, 3, 4, 9, 12]
 * 第三遍:[2, 4, 7, 3, 4, 8, 9, 12]
 * 第四遍:[2, 4, 3, 4, 7, 8, 9, 12]
 * 第五遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第六遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第七遍:[2, 3, 4, 4, 7, 8, 9, 12]
* 紫色代表上轮排好序的数组,红色代表本轮最大元素
*
* 最好:O(n) 最坏:O(n^2) 平均:O(n^2)
*/ public class BubbleSort { public void bubbleSort(int[] array) { int temp; for (int i = 0; i < array.length - 1; i++) { for (int j = 0; j < array.length - i - 1; j++) { if (array[j] > array[j + 1]) { temp = array[j + 1]; array[j + 1] = array[j]; array[j] = temp; } } } } }

 插入排序:

/**
 * 插入排序
 * 原理:从第二个数开始比较,循环n-1次,每次将有序数组的后一位数x与前面的有序数组(数组从后往前的顺序)比较,然后在不比x大的数后进行插入。
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4],第一遍判断的元素为2
 * 第一遍:[2, 9, 4, 7, 12, 8, 3, 4],第二遍判断的元素为4
 * 第二遍:[2, 4, 9, 7, 12, 8, 3, 4],第三遍判断的元素为7
 * 第三遍:[2, 4, 7, 9, 12, 8, 3, 4],第四遍判断的元素为12
 * 第四遍:[2, 4, 7, 9, 12, 8, 3, 4],第五遍判断的元素为8
 * 第五遍:[2, 4, 7, 8, 9, 12, 3, 4],第六遍判断的元素为3
 * 第六遍:[2, 3, 4, 7, 8, 9, 12, 4],第七遍判断的元素为4
 * 第七遍:[2, 3, 4, 4, 7, 8, 9, 12]
* 紫色为本轮排好序的数组,红色为下轮需要判断的元素
*
* 最好:O(n) 最坏:O(n^2) 平均:O(n^2)
*/ public class InsertSort { public void insertSort(int[] array) { int i, j;int currentNum; for (i = 1; i < array.length; i++) {// i位置上的元素就是当前要判断的值 currentNum = array[i]; for (j = i; j > 0 && currentNum < array[j - 1]; j--) { array[j] = array[j - 1]; } array[j] = currentNum; } } }

 希尔排序:

/**
 * 希尔排序
 * 原理:比较复杂,是插入排序的升级版(分组插入排序),下面代码步长是以(数组长度/2)开始,分组、排序后将步长除以2,再分组、排序,直到步长为1时(就是插入排序)。
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4] 步长为8/2 = 4进行分割
 * 将8个数据分为ABCD四组,A:(9 12) B:(2 8) C:(4 3) D:(7 4)。分组插入排序后A:(9 12) B:(2 8) C:(3 4) D:(4 7)
 * 数组为:[9, 2, 3, 4, 12, 8, 4, 7] 步长为2进行分割
 * 将8个数据分为AB两组,A:(9 3 12 4) B:(2 4 8 7)。分组插入排序后A:(3 4 9 12) B:(2 4 7 8)
 * 数组为:[3, 2, 4, 4, 9, 7, 12, 8] 步长为1进行分割
 * 将8个数据进行插入排序(2, 3, 4, 4, 6, 7, 8, 9, 12)
 * 最终数组:[2, 3, 4, 4, 6, 7, 8, 9, 12]
* 相同的颜色代表他们在下次分割之后分为同一组进行插入排序
*
* 最好O(n) 最坏O(n^2) 平均O(n^1.3)
*/ public class ShellSort { public void shellSort(int[] array) { int k, i, j; int currentNum; for (int gap = array.length / 2; gap > 0; gap /= 2) {// 步长分别为4、2、1循环三次 for (k = 0; k < gap; k++) {// 多少步长相当于分为几组,比如第一次分为4组,循环4次来分别对4组进行插入排序 for (i = k + gap; i < array.length; i += gap) {// 进行分组插入排序,比如第一次先用array[4]为当前数与前面比较 currentNum = array[i];// 现将需要插入的数存起来 for (j = i; j > 0; j -= gap) {// 若前面的数索引大于0则继续比较 if (j - gap < 0) {// 一会涉及到j-gap操作,有可能j>0而j-gap<0而导致数组越界,所以需要判断 break; } else if (currentNum < array[j - gap]) {// 若插入的数小于前面的数 array[j] = array[j - gap];// 将前面的数向后移动,由于事先存入需要插入的数的数据,所以不用担心。 } else { break;// 若前面的数小于需要插入的数了则跳出循环 } } array[j] = currentNum;// 将需要插入的数插入到它应该在的地方 } } } } }

 快速排序:

/**
 * 快速排序
 * 原理:先随便选择一个元素作为基准值,排完序后所有比基准值小的放在前面,大的放后面。
 * 再用递归把小于基准值元素的子数列和大于基准值元素的子数列排序,最后数列的大小是零或一就说明排序好了。
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4],选基准值为9
 * 第一遍:[4, 2, 4, 7, 3, 8, 9, 12],子数列:[4, 2, 4, 7, 3, 8] 和 [12]
 * 第二遍:[3, 2, 4, 4, 7, 8, 9, 12],子数列:[3, 2, 4] [7, 8]
 * 第三遍:[2, 3, 4, 4, 7, 8, 9, 12],子数列:[2] [4] [8]、
* 紫色是被基准值分为的两个子数列,红色是基准值最后的位置
*
* 最好:O(nlogn) 最坏:O(n^2) 平均:O(nlogn)
*/ public class QuickSort { public void quickSort(int[] array, int min, int max) { if (min >= max) { return; } int i = min; int j = max; int key = array[i]; while (i < j) { while (i < j && key <= array[j]) { j--; } array[i] = array[j]; while (i < j && key >= array[i]) { i++; } array[j] = array[i]; } array[i] = key; quickSort(array, min, i - 1); quickSort(array, i + 1, max); } }

 归并排序:

/**
 * 归并排序  采用分治法(Divide and Conquer)
 * 原理:每次将数组二分为两个子数组,再递归二分子数组,直到分成每一个数组只有一个元素为止,然后将相邻两数组进行合并为有序数组,反复合并,最后合并为一个完整有序数组
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4]
 * 递归1: [9, 2, 4, 7] [12, 8, 3, 4]
 * 递归2: [9, 2] [4, 7] [12, 8] [3, 4]
 * 递归3: [9] [2] [4] [7] [12] [8] [3] [4]
 * 合并1: [2, 9] [4, 7] [8, 12] [3, 4]
 * 合并2: [2, 4, 7, 9] [3, 4, 8, 12]
 * 合并3: [2, 3, 4, 4, 7, 8, 9, 12]
*
* 最好:O(nlogn) 最坏:O(nlogn) 平均:O(nlogn)
*/ public class MergeSort { /** * @param array 原数组 * @param min 此次排序的数组最小索引 * @param mid 此次排序的数组中间索引 * @param max 此次排序的数组最大索引 * @param p 进行循环利用的数组 * eg: [1,2,3,4,5,6]是原数组,[1,2,3]是此次排序数组,[1,2]与[3]为子数组,1是min,2是mid,3是max */ public void merge(int[] array, int min, int mid, int max, int[] p) { int i = min, j = mid + 1;// i为子数组[min,mid]的最小索引,j为子数组[mid+1,max]的最小索引 int u = 0;// 将p数组的索引指向0 while (i <= mid && j <= max) {// 若两个子数组都有值,则比较谁索引上的值比较小,小的放入p数组中,并将其索引与p的索引值+1 if (array[i] <= array[j]) { p[u++] = array[i++]; } else { p[u++] = array[j++]; } } while (i <= mid) {// 若子数组[min,mid]还有剩余值,而[mid+1,max]无剩余值,则将剩下的元素都放入p数组中 p[u++] = array[i++]; } while (j <= max) {// 若子数组[mid+1,max]还有剩余值,而[min,mid]无剩余值,则将剩下的元素都放入p数组中 p[u++] = array[j++]; } for (i = 0; i < u; i++) {// [min,mid]与[mid+1,max]都放入p数组之后,将排好序的p数组覆盖原数组中此次需要排序数组 array[min + i] = p[i]; } } /** * @param array 原数组 * @param min 数组起始索引 * @param max 数组末尾索引 * @param p 空数组p */ public void mergeSort(int[] array, int min, int max, int[] p) { if (min < max) {// 若是起始索引小于末尾索引,就说明该数组元素个数大于1,还需要再分 int mid = (min + max) >> 1;// 取中间数,将以中间数为界分成两个子数组[min,mid] [mid+1,max] mergeSort(array, min, mid, p);// 对子数组[min,mid]进行递归,最终将[min,mid]拆分为单个元素后,合并为一个有序数列 mergeSort(array, mid + 1, max, p);// 对子数组[mid+1,max]进行递归,最终将[mid+1,max]拆分为单个元素后,合并成一个有序数列 merge(array, min, mid, max, p);// 在最外层,将子数组[min,mid]与[mid+1,max]合并为有序数列 } } // 归并函数入口,就将需要排序的数组传入 public void Merge(int[] array) { int length = array.length; int p[] = new int[length];// 开一个和需要排序数组一样大的空数组,并在接下来进行循环利用。 mergeSort(array, 0, length - 1, p);// 参数:数组,数组起始索引,数组末尾索引,数组p } @Test public void test() { int[] array = new int[]{9, 2, 4, 7, 12, 8, 3, 4}; Merge(array); System.out.println(Arrays.toString(array)); } }

 堆排序:

/**
 * 堆排序
 * 原理:将数组调整为大顶堆,将堆顶元素和末尾元素交换,再将[0-(n-1)]个元素调整为大顶堆,再交换。依此类推...
 * 学前知识:用数组模仿完全二叉树,完全二叉树是除h层外,其他各层节点数都达到最大个数。第h层节点个数都连续集中在最左边。
 *         子节点与父节点关系:i --- 2*i+1 --- 2*i+2
 *         最后一个非叶子节点:array[].length/2-1
 * 原数组:[9, 2, 4, 7, 12, 8, 3, 4]
 * 第一遍:[4, 9, 8, 7, 2, 4, 3, 12]
 * 第二遍:[3, 7, 8, 4, 2, 4, 9, 12]
 * 第三遍:[3, 7, 4, 4, 2, 8, 9, 12]
 * 第四遍:[2, 4, 4, 3, 7, 8, 9, 12]
 * 第五遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第六遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第七遍:[2, 3, 4, 4, 7, 8, 9, 12]
 * 第八遍:[2, 3, 4, 4, 7, 8, 9, 12]
* 紫色为当前排序好的有序数组
* 最好:O(nlogn) 最坏:O(nlogn) 平均:O(nlogn)
*/ public class HeapSort { public void heapSort(int[] array) { // 构建大顶堆,从最后一个非叶子节点到根节点依次调整 for (int i = array.length / 2 - 1; i >= 0; i--) { adjustHeap(array, i, array.length); } // 在调整好堆结构后,交换堆顶元素和末尾元素,再对堆顶元素进行调整 for (int j = array.length - 1; j > 0; j--) { swap(array, 0, j); adjustHeap(array, 0, j); } } /** * @param array 原数组 * @param i 所需调整的非叶子节点 * @param length 子数组长度 */ public void adjustHeap(int[] array, int i, int length) { int temp = array[i];// 将i的值进行备份 for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {// k指向i的左子节点 if (k + 1 < length && array[k] < array[k + 1]) {// 比较左子节点和右子节点谁大,谁大k指向该节点 k++; } if (array[k] > temp) {// 将较大的子节点的值和父节点进行比较,若大于父节点则进行覆盖 array[i] = array[k]; i = k; } else {// 否则终止循环 break; } } array[i] = temp;// 将temp的值放到最终位置 } /** * @param array 原数组 * @param a 堆顶元素 * @param b 当前子数组中最后一位元素 */ public void swap(int[] array, int a, int b) { int temp = array[a]; array[a] = array[b]; array[b] = temp; } }

 

posted @ 2018-09-12 09:52  JimHan  Views(242)  Comments(0Edit  收藏  举报