Java中10個經常使用的排序算法
摘要:算法在平常的編程中是很是重要的一個知識點,今天讓咱們一塊兒重溫排序,下面是用java實現的經常使用的十個算法案例:
import java.util.ArrayList;
import java.util.Arrays;
public class Sort {
public static void main(String[] args) {
int[] arr = new int[20];
int index = 0;
for(int i = 20;i > 0;i--)
arr[index++] = i;
System.out.println("原數組:");
System.out.println(Arrays.toString(arr));
System.out.println("開始排序");
arr = InsertionSort(arr);
System.out.println("排序後爲:");
System.out.println(Arrays.toString(arr));
}
// 工具:交換數組中元素的位置
public static int[] swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
// ****** 1.直接插入排序 ******
public static int[] InsertionSort(int[] arr){
if(arr.length == 0 || arr.length == 1)
return arr;
for(int i = 0;i < arr.length - 1;i++){
// 將 i+1 位置的數插入 0 到 i 之間的數組,從後往前遍歷
// current 指 i+1 的位置元素,pre 指 0 到 i 中依次向前遍歷的指針
int current = arr[i+1];
int pre = i;
while(pre >= 0 && current < arr[pre]){
arr[pre+1] = arr[pre];
pre--;
}
// 最後將原來 i+1 位置的元素放入如今 0 到 i+1 之間數組中正確的位置上
// pre+1 是由於剛纔循環結束時又自減了一次
arr[pre+1] = current;
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
}
return arr;
}
// ****** 2.希爾排序 ******
// 希爾排序最重要的變量就是 gap,全部須要+1或者自加1的地方都要注意
public static int[] ShellSort(int[] arr){
if(arr.length == 0 || arr.length == 1)
return arr;
int current, gap = arr.length / 2;
while(gap > 0){
for(int i = gap;i < arr.length;i++){
// 將 pre+gap 位置的數插入 0 到 pre 之間「同組」的數組,從後往前遍歷
// current 指 pre+gap 的位置元素
current = arr[i];
int pre = i - gap;
while(pre >= 0 && arr[pre] > current){
arr[pre+gap] = arr[pre];
pre -= gap;
}
arr[pre+gap] = current;
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
}
gap /= 2;
}
return arr;
}
// ****** 3.簡單選擇排序 ******
public static int[] SelectionSort(int[] arr){
if(arr.length == 0 || arr.length == 1)
return arr;
for(int i = 0;i < arr.length - 1;i++){
// 每一輪挑出一個最小的元素,依次與不斷增加的 i 位置的元素交換
int MinIndex = i;
for(int j = i;j < arr.length;j++){
if(arr[j] < arr[MinIndex])
MinIndex = j;
}
arr = swap(arr,MinIndex,i);
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
}
return arr;
}
// ****** 4.堆排序 ******
// 主函數
public static int[] HeapSort(int[] arr){
if(arr.length == 0 || arr.length == 1)
return arr;
int len = arr.length;
// 堆排序第一步是先把當前數組變成一個最大堆
arr = AdjustMaxHeap(arr, len-1);
while(len > 0){
// 取出堆頂的元素(最大元素)與末尾尚未肯定位置的元素交換
arr = swap(arr,0,len - 1);
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
len--;
arr = AdjustMaxHeap(arr,len - 1);
}
return arr;
}
// 調整爲最大堆
public static int[] AdjustMaxHeap(int[] arr, int lastIndex){
for(int i = (lastIndex - 1) / 2;i>=0;i--){
arr = AdjustLocalHeap(arr,lastIndex,i);
}
return arr;
}
//調整局部堆使其成爲局部最大堆
/*
注意事項:堆中結點是從 1 開始的,但把數組看做堆的話,數組的下標是從 0 開始的
那麼父結點與子結點的關係就會發生變化:
父結點 = (子結點-1)/2
左子結點 = 父結點*2+1
右子結點 = 父結點*2+2
*/
public static int[] AdjustLocalHeap(int[] arr,int lastIndex,int i){
// 找出當前結點和左右子結點(若是有左右子結點的話)中最大的元素,讓這個最大的元素成爲父結點
int maxIndex = i;
if(i*2+1 <= lastIndex && arr[i] < arr[i*2+1])
maxIndex = i*2+1;
// 這裏要多一個右子結點是否大於左子結點的斷定
if(i*2+2 <= lastIndex && arr[i] < arr[i*2+2] && arr[i*2+1] < arr[i*2+2])
maxIndex = i*2+2;
// 若是父結點不是三個結點中的最大結點,那麼將最大結點變成父結點
// 再經過遞歸看看這個比較小的父結點能不能再「往下沉」
if(maxIndex != i){
arr = swap(arr,maxIndex,i);
arr = AdjustLocalHeap(arr,lastIndex,maxIndex);
}
return arr;
}
// ****** 5.冒泡排序 ******
public static int[] BubbleSort(int[] arr){
if(arr.length == 0 || arr.length ==1)
return arr;
for(int i = arr.length-1;i > 0;i--){
for(int j = 1;j <= i;j++){
if(arr[j] < arr[j-1])
arr = swap(arr,j,j-1);
}
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
}
return arr;
}
// ****** 6.快速排序 ******
//主函數
public static int[] QuickSort(int[] arr){
if(arr.length == 0 || arr.length ==1)
return arr;
arr = LocalQuickSort(arr,0,arr.length -1 );
return arr;
}
// 快速排序
public static int[] LocalQuickSort(int[] arr, int start, int last){
if(start >= last)
return arr;
// benchmark 指基準數,也就是這一輪將要肯定位置的數
int benchmark = start;
int left = start;
int right = last;
while(left < right){
// 必須右指針先走
while(arr[right] > arr[benchmark] && left < right) right--;
if(arr[right] <= arr[benchmark] && left < right) arr[left++] = arr[right];
while(arr[left] < arr[benchmark] && left < right) left++;
if(arr[right] >= arr[benchmark] && left < right) arr[right--] = arr[left];
}
arr[left] = arr[benchmark];
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
// 經過遞歸,分別對已肯定位置的數的兩邊區域進行快速排序
arr = LocalQuickSort(arr,start,left-1);
arr = LocalQuickSort(arr,left+1,last);
return arr;
}
// ****** 7.歸併排序 ******
// 主函數
public static int[] MergeSort(int[] arr){
if(arr.length == 0 || arr.length ==1)
return arr;
arr = Merge(arr,0,arr.length-1);
return arr;
}
// 歸併排序
public static int[] Merge(int[] arr,int start,int last){
// start < last 的判斷意味着 arr 指定的範圍內必須至少有兩個元素
if(start < last){
int mid = (start + last) / 2;
// 左右部分分別遞歸
arr = Merge(arr,start,mid);
arr = Merge(arr,mid+1,last);
// 遞歸層面:從裏往外依次將左半部分和右半部分整合成一個部分
arr = merge(arr,start,mid,last);
}
return arr;
}
public static int[] merge(int[] arr,int start,int mid,int last){
// tempArr 指一個額外數組,用來臨時給 arr 中同一區域的元素排序
int[] tempArr = new int[arr.length];
// p1 指 arr 指定區域的左半部分的指針,p2 指 arr 指定區域的右半部分的指針,p 指額外數組 tempArr 的指針
int p1 = start, p2 = mid+1, p = start;
// 從指定區域的左右半部分中取出最小元素放入額外數組,完成指定區域內的排序
while(p1 <= mid && p2 <= last){
if(arr[p1] <= arr[p2])
tempArr[p++] = arr[p1++];
else
tempArr[p++] = arr[p2++];
}
while(p1 <= mid) tempArr[p++] = arr[p1++];
while(p2 <= last) tempArr[p++] = arr[p2++];
// 將額外數組中的數據覆蓋到原 arr 數組中
for(int i = start;i <= last;i++)
arr[i] = tempArr[i];
System.out.println(Arrays.toString(arr));
return arr;
}
// ****** 8.基數排序 ******
public static int[] RadixSort(int[] arr){
if(arr.length == 0 || arr.length ==1)
return arr;
// max 指數組中最大的數,maxDigit 指這個最大的數是幾位數
int max = arr[0];
for(int x:arr)
max = Math.max(x,max);
int maxDigit = 0;
while(max != 0){
max /= 10;
maxDigit++;
}
// mod 用於爲數組中的數取餘數,div 用於把經過 mod 取的餘數變成個位數
int mod = 10;
int div = 1;
ArrayList<ArrayList<Integer>> bucket = new ArrayList<ArrayList<Integer>>();
for(int j = 0;j < 10;j++){
bucket.add(new ArrayList<Integer>());
}
for(int i = 0;i<maxDigit;i++,mod *= 10,div *= 10){
// 打印這一輪的排序結果
System.out.println(Arrays.toString(arr));
for(int j = 0;j < arr.length;j++){
// num 指當前元素 arr[j] 的個/十/百/千位是幾
int num = (arr[j] % mod) / div;
bucket.get(num).add(arr[j]);
}
int index = 0;
for(int j = 0;j < 10;j++){
if(bucket.get(j).size() != 0){
for(int x:bucket.get(j))
arr[index++] = x;
// 將桶中全部的動態數組清空,不然第二次循環開始再用到這些動態數組時裏面還會有數據
bucket.get(j).clear();
}
}
}
return arr;
}
// ****** 9.計數排序 ******
public static int[] CountingSort(int[] arr){
if(arr.length ==0 || arr.length == 1)
return arr;
int min, max;
min = max = arr[0];
for(int x: arr){
if(x > max)
max = x;
if(x < min)
min = x;
}
// bucket 指用來存儲每一個元素出現次數的桶,長度爲元素的範圍
int[] bucket = new int[max - min +1];
// 把 bucket 用 0 填滿,由於以後要累加
Arrays.fill(bucket,0);
// 在 bucket 中相應的位置記錄每一個元素出現的次數
for(int x:arr){
bucket[x - min]++;
}
int index = 0;
// 依次從 bucket 中提取元素覆蓋到原來的 arr 上
for(int i =0;i<bucket.length;i++){
while(bucket[i] != 0){
arr[index++] = i + min;
bucket[i]--;
}
}
return arr;
}
// ****** 10.桶排序 ******
// 主函數
public static int[] BucketSort(int[] arr){
if(arr.length == 0 || arr.length == 1)
return arr;
arr = Bucket(arr,5);
return arr;
}
// 桶排序
// bucketSize 指每一個桶的容量,bucketCount 指桶的個數
public static int[] Bucket(int[] arr,int bucketSize){
int min,max;
min = max = arr[0];
for(int x:arr){
if(x > max)
max = x;
if(x > min)
min = x;
}
int bucketCount = (max - min) / bucketSize +1;
ArrayList<ArrayList<Integer>> bucket = new ArrayList<ArrayList<Integer>>();
for(int i = 0;i < bucketCount;i++)
bucket.add(new ArrayList<Integer>());
for(int x: arr){
// 遍歷每一個桶
for(int bucketIndex = 0;bucketIndex < bucketCount;bucketIndex++){
// 若是 arr 當前元素在該桶的範圍內,則將該元素放入該桶內,並結束遍歷每一個桶的循環
if(x >= min + bucketIndex*bucketSize && x < min + (bucketIndex+1)*bucketSize){
bucket.get(bucketIndex).add(x);
break;
}
}
}
int index = 0;
for(int i = 0;i < bucketCount;i++){
// 對每一個桶使用直接插入排序,調整桶內元素的順序
bucket.set(i,InsertionSortOfArrayList(bucket.get(i)));
for(int x:bucket.get(i))
arr[index++] = x;
}
return arr;
}
// 針對動態數組的直接插入排序
public static ArrayList<Integer> InsertionSortOfArrayList(ArrayList<Integer> arr){
if(arr.size() == 0 || arr.size() ==1)
return arr;
int current;
int pre;
for(int i = 0;i < arr.size() - 1;i++){
pre = i;
current = arr.get(i+1);
while(arr.get(pre) > current && pre >= 0){
arr.set(pre+1,arr.get(pre));
pre--;
}
arr.set(pre+1,current);
}
return arr;
}
}