排序算法(Java实现)
这几天一直在看严蔚敏老师的那本《数据结构》那本书。之前第一次学懵懵逼逼,当再次看的时候,发觉写的是非常详细,非常的好。
那就把相关的排序算法用我熟悉的Java语言记录下来了。以下排序算法是我认为比较重要的,而且在面试中比较容易考的算法。
- 冒泡排序
- 快速排序
- 堆排序
- 归并排序
(一)前言
排序其实是一个相当大的概念,主要分为两类:内部排序和外部排序。而我们通常所说的各种排序算法其实指的是内部排序算法。内部排序是基于内存的,整个排序过程都是在内存中完成的,而外部排序指的是由于数据量太大,内存不能完全容纳,排序的时候需要借助外存才能完成(常常是算计着某一部分已经计算过的数据移出内存让另一部分未被计算的数据进入内存)。而我们本篇文章将主要介绍内排序中的几种常用排序算法:
(二)冒泡排序
最经典的排序方法,没有之一,所有人学排序的第一个算法。
比较简单直接看代码吧。
1 public class Main { 2 public static void main(String[] args) { 3 4 int[] a = {7, 6, 9, 3, 2, 11, 9}; 5 Bubble b = new Bubble(); 6 b.bubbleSort(a); 7 for (int i = 0; i < a.length; i++) { 8 System.out.print(a[i] + " "); 9 } 10 System.out.println(); 11 } 12 } 13 14 class Bubble { 15 16 int[] bubbleSort(int[] a) { 17 for (int i = 0; i < a.length - 1; i++) { 18 for (int j = i + 1; j < a.length; j++) { 19 if (a[i] > a[j]) { 20 swap(a, i, j); 21 } 22 } 23 } 24 return a; 25 } 26 27 void swap(int[] a, int i, int j) { 28 int t = 0; 29 t = a[i]; 30 a[i] = a[j]; 31 a[j] = t; 32 } 33 }
(三)快速排序
史上最快的排序算法之一,称为快速排序。连Arrays.sort底层都是快速排序,不过有进行改进(DualPivotQuicksort三千多行代码,向大神跪了)
快速排序的基本思想是,从序列中任选一个元素,但通常会直接选择序列的第一个元素作为一个标准,所有比该元素值小的元素全部移动到他的左边,比他大的都移动到他的右边。我们称这叫做一趟快速排序,位于该元素两边的子表继续进行快速排序算法直到整个序列都有序。该排序算法是目前为止,内部排序中效率最高的排序算法。具体它是怎么做的呢?
首先他定义了两个头尾指针,分别指向序列的头部和尾部。从high指针位置开始扫描整个序列,如果high指针所指向的元素值大于等于临界值,指针前移。如果high指针所指向的元素的值小于临界值的话:
将high指针所指向的较小的值交换给low指针所指向的元素值,然后low指针前移。
然后重复上述过程,直至x=48左边全部小于他,右边全部大于他。看代码
1 class Quick { 2 3 int[] quickSort(int[] a, int left, int right) { 4 5 if (left < right) { 6 int pos = postion(a, left, right); 7 quickSort(a, left, pos - 1); 8 quickSort(a, pos + 1, right); 9 } 10 return a; 11 } 12 13 int postion(int[] a, int left, int right) { 14 15 int t = a[left]; 16 while (left < right) { 17 while (left < right && t <= a[right]) --right; 18 a[left] = a[right]; 19 while (left < right && t >= a[left]) ++left; 20 a[right] = a[left]; 21 } 22 a[left] = t; 23 return left; 24 } 25 26 }
(四)堆排序
先了解下什么叫做堆。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
大根堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小根堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
堆排序我自认为理解了,但写起博客有些麻烦,大家想要了解可以去 这里看看 堆排序算法,我觉的写的挺好的
我这里直接用PriorityQueue
1 class Heap { 2 3 int[] heapSort(int[] a) { 4 5 int[] t = new int[a.length]; 6 PriorityQueue<Integer> pq = new PriorityQueue<>(a.length); 7 //建堆 8 for (int i = 0; i < a.length; i++) { 9 pq.add(a[i]); 10 } 11 int cnt = 0; 12 //出堆后破坏了堆的定义,那就调整堆 13 while (!pq.isEmpty()) { 14 t[cnt++] = pq.poll(); 15 } 16 return t; 17 } 18 }
(五)归并排序
这里的归并类排序算法指的就是归并排序。归并排序的核心思想是,对于一个初始的序列不断递归,直到子序列中的元素足够少时,对他们进行直接排序。然后递归返回继续对两个分别有序的序列进行直接排序,最终递归结束的时候,整个序列必然是有序的。就是分而治之
1 /*归并排序的递归调用*/ 2 public static void MergeSort(int[] array,int low,int high){ 3 if(low == high){ 4 //说明子数组长度为1,无需分解,直接返回即可 5 }else{ 6 int p = (low+high)/2; 7 MergeSort(array,low,p); 8 MergeSort(array,p+1,high); 9 //完成相邻两个子集合的归并 10 MergeTwoData(array,low,high); 11 } 12 } 13 /*用于排序两个子序列的归并排序算法实现*/ 14 public static void MergeTwoData(int[] array,int low,int high){ 15 int[] arrCopy = new int[high-low+1]; 16 int i,j; 17 i = low;j= (low+high)/2+1; 18 for (int key=0;key<=high-low;key++){ 19 //如果左边子数组长度小于右边数组长度,当左数组全部入库之后,右侧数组不用做比较直接入库 20 if(i==(low+high)/2+1){ 21 arrCopy[key] = array[j]; 22 j++; 23 } 24 //如果右侧数组长度小于左侧数组长度,当右侧数组全部入库之后,左侧数组不用做比较直接入库 25 else if(j==high+1){ 26 arrCopy[key]=array[i]; 27 i++; 28 }else if(array[i]<array[j]){ 29 arrCopy[key]=array[i]; 30 i++; 31 }else{ 32 arrCopy[key] = array[j]; 33 j++; 34 } 35 } 36 j = 0; 37 //按顺序写回原数组 38 for(int x=low;x<=high;x++) { 39 array[x] = arrCopy[j]; 40 j++; 41 } 42 }