一、快速排序
快速排序算法通過多次比較和交換來實現排序,其排序流程如下:
1.首先設定一個分界值,通過該分界值將數組分成左右兩部分。
2.將大於或等於分界值的數據集中到數組右邊,小於分界值的數據集中到數組的左邊。此時,左邊部分中各元素都小於或等於分界值,而右邊部分中各元素都大於或等於分界值。
3.然後,左邊和右邊的數據可以獨立排序。對於左側的數組數據,又可以取一個分界值,將該部分數據分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側的數組數據也可以做類似處理。
4.重複上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側部分排好序後,再遞歸排好右側部分的順序。當左、右兩個部分各數據排序完成後,整個數組的排序也就完成了。
public class QuickSort {
public static void main(String[] args) {
// int[] arrays = {101, 34, 119, 1};
// int[] result = insertSort(arrays);
// System.out.println(Arrays.toString(result));
//速度測試 8049
long begin = System.currentTimeMillis();
int[] array = new int[8];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] results = quickSort(array,0,array.length-1);
long end = System.currentTimeMillis();
System.out.println("用時:"+(end - begin));
System.out.println(Arrays.toString(results));
}
public static int[] quickSort(int[]arr,int left,int right){
// System.out.println(Arrays.toString(arr));
//左下標
int lIndex = left;
//右下標
int rIndex = right;
//pivot中軸值
int pivot = arr[(left + right) / 2];
//臨時變量
int temp = 0;
//while循環的目的是讓比pivot值小放到左邊,比pivot大的放到右邊
while(lIndex < rIndex){
//pivot的左邊一直找,找到>=pivot的值時退出
while (arr[lIndex] < pivot){
lIndex += 1;
}
while (arr[rIndex] > pivot){
rIndex -= 1;
}
// System.out.println(Arrays.toString(arr));
//若lIndex>=rIndex說明左邊已經全部都是小於pivot的值,右邊已全部都是大於pivot的值
if(lIndex >= rIndex){
break;
}
//進行值的交換
temp = arr[lIndex];
arr[lIndex] = arr[rIndex];
arr[rIndex] = temp;
//交換完成後若arr[lIndex] == pivot 相同,說明pivot左邊已完成排序,右邊的指針前移
if(arr[lIndex] == pivot){
rIndex -= 1;
}
//交換完成後若arr[rIndex] == pivot 相同,說明pivot右邊已完成排序,左邊的指針後移
else if(arr[rIndex] == pivot){
lIndex += 1;
}
}
//如果lIndex == rIndex ,需將左指針後移 ,右指針前移 避免出現棧溢出
if(lIndex == rIndex){
lIndex++;
rIndex--;
}
//若右指針比初始的做指針大,說明左邊沒有進行排序
if(left < rIndex){
quickSort(arr,left,rIndex);
}
if(right > lIndex){
quickSort(arr,lIndex,right);
}
return arr;
}
}
二、歸併排序
歸併操作的工作原理如下:
1.申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
2.設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
3.比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
4.重複步驟3直到某一指針超出序列尾
5.將另一序列剩下的所有元素直接複製到合併序列尾
public class MergeSort {
public static void main(String[] args) {
// int[] arrays = {101, 34, 119, 1};
// int[] temp = new int[arrays.length];
// mergeSort(arrays, 0, arrays.length - 1, temp);
// System.out.println(Arrays.toString(arrays));
//速度測試 8049
long begin = System.currentTimeMillis();
int[] array = new int[80000];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] temp = new int[array.length];
mergeSort(array, 0, array.length - 1, temp);
long end = System.currentTimeMillis();
System.out.println("用時:" + (end - begin));
// System.out.println(Arrays.toString(array));
}
public static void mergeSort(int[] arrays, int left, int right, int[] temp) {
if (left < right) {
int pivot = (left + right) / 2;
mergeSort(arrays, left, pivot, temp);
mergeSort(arrays, pivot + 1, right, temp);
merge(arrays, left, pivot, right, temp);
}
}
public static void merge(int[] arrays, int left, int pivot, int right, int[] temp) {
//初始化左邊有序序列的初始索引
int leftIndex = left;
//初始化右邊有序序列的初始索引
int rightIndex = pivot + 1;
//指向temp數組的當前索引
int tempIndex = 0;
//一.先把左右兩邊(有序)的數組按照規則填充到temp數組中
//直到左右兩邊的有序序列,有一邊處理完成爲止
while (leftIndex <= pivot && rightIndex <= right) {
if (arrays[leftIndex] <= arrays[rightIndex]) {
temp[tempIndex] = arrays[leftIndex];
leftIndex++;
tempIndex++;
} else {
temp[tempIndex] = arrays[rightIndex];
rightIndex++;
tempIndex++;
}
}
while (leftIndex <= pivot) {
temp[tempIndex] = arrays[leftIndex];
tempIndex++;
leftIndex++;
}
while (rightIndex <= right) {
temp[tempIndex] = arrays[rightIndex];
tempIndex++;
rightIndex++;
}
tempIndex = 0;
int tempLeft = left;
while (tempLeft <= right) {
arrays[tempLeft] = temp[tempIndex];
tempIndex++;
tempLeft++;
}
}
}
三、桶排序/基數排序
基本思想:先排好個位,再排十位,百位,千位…
1.創建10個的桶,下標從0到9。
2.遍歷原數據,獲取元素的個位,將其放入匹配下標的桶中。
3.全部放入之後再取出替換原數據,再將排序過一次的原數據遍歷,獲取元素的十位,將其放入匹配下標的桶中,依次百位,千位…
4.最後一次放到桶中,再按照桶的下標從0-9將其中的數據取出,就獲得到了有序數列。
public class RadixSort {
public static void main(String[] args) {
/*
int[] arrays = {101, 34, 119, 1};
int[] result = radixSort(arrays);
System.out.println(Arrays.toString(result));
*/
//速度測試 91
long begin = System.currentTimeMillis();
int[] array = new int[8000000];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 8000000);
}
int[] results = radixSort(array);
long end = System.currentTimeMillis();
System.out.println("用時:"+(end - begin));
// System.out.println(Arrays.toString(results));
}
public static int[] radixSort(int[] arrays) {
//數組中最大數
int max = arrays[0];
for (int i = 1; i < arrays.length; i++) {
if (arrays[i] > max) {
max = arrays[i];
}
}
//最大數是幾位數
int maxLength = (max + "").length();
// 定義10個桶,每個桶是一個數組
/*說明
1. 二維數組包含10個一維數組
2. 爲了防止在放入數的時候,數據溢出,則每個一維數組(桶),大小定爲arrays.length
3. 明確,基數排序是使用空間換時間的經典算法
*/
int[][] bucket = new int[10][arrays.length];
//定義一個數組記錄每個桶實際存放的數據個數
int[] bucketCounts = new int[10];
//取出數據用
int index = 0;
//使用循環進行排序
for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
//針對每個元素對應的位數進行處理,第一次處理個位數,第二次處理十位,以此類推
for (int j = 0; j < arrays.length; j++) {
//取出每個元素對應位數的值
int digitOfElement = arrays[j] / n % 10;
//將其放入對應的桶中
bucket[digitOfElement][bucketCounts[digitOfElement]] = arrays[j];
//將指針向前移動一下
bucketCounts[digitOfElement]++;
}
//按照這個桶的順序(一維數組的下標依次取出數據,放入到原來的數組中)
index = 0;
//遍歷每一個桶中的數據
for (int k = 0; k < bucketCounts.length; k++) {
//只有桶中有數據時才放入原數組
if(bucketCounts[k]!=0){
//循環第k個桶
for (int l = 0;l < bucketCounts[k];l++){
//取出元素放入arrays
arrays[index++] = bucket[k][l];
}
}
//第i+1輪處理後將桶的指針回到初始位置
bucketCounts[k] = 0;
}
}
return arrays;
}
}