【Java資料結構與演算法】第八章 快速排序、歸併排序和基數排序

tankII發表於2021-09-09

第八章 快速排序、歸併排序和基數排序
文章目錄
第八章 快速排序、歸併排序和基數排序
一、快速排序
1.基本介紹
2.程式碼實現
二、歸併排序
1.基本介紹
2.程式碼實現
三、基數排序
1.基本介紹
2.程式碼實現
一、快速排序
1.基本介紹
快速排序(Quick Sort)是在氣泡排序基礎上的遞迴分治法,其基本原理:選擇一個關鍵值作為基準值。比基準值小的都在左邊序列, 比基準值大的都在右邊

當一個等於基準元素的元素在基準元素的右邊時,由於小於等於基準元素的元素都要移動到基準元素左邊,所以該元素和基準元素的相對位置就改變了,因此快速排序是一種不穩定的排序演算法

演算法步驟

從數列中挑出一個元素,稱為 “基準”(pivot)
重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作
遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序

2.程式碼實現
package com.sisyphus.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;


public class QuickSort {
public static void main(String[] args) {
//int[] arr = {-9, 78, 0, 23, -567, 70, -1, 900, 4561};
//quickSort(arr,0,arr.length -1);
(Arrays.toString(arr));

 //建立一個 80000 個隨機數的陣列
 int[] arr = new int[80000];
 for (int i = 0; i 

}


public static void quickSort(int[] arr,int left, int right){
int l =left;
int r = right;
int pivot = arr[(left + right) / 2];
int temp = 0;//用於交換
//while 迴圈的目的是讓比 pivot 小的值放到左邊,比 pivot 大的值放到右邊
while(l //在 pivot 左邊一直找,找到一個大於等於 pivot 的值才退出
while (arr[l] l += 1;
}
//在 pivot 右邊一直找,找到一個小於等於 pivot 的值才退出
while(arr[r] > pivot){
r -= 1;
}
//如果 l >= r 說明 pivot 左右兩邊的值已經按照左邊全是小於等於 pivot,右邊全是大於等於 pivot 的規定排列好了
if(l >= r){
break;
}
//交換
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;

 //如果交換完後,發現 arr[l] == pivot
 if (arr[l] == pivot){
     r -= 1;
 }
 //如果交換完後,發現 arr[r] == pivot
 if (arr[r] == pivot){
     l += 1;
 }

}

//如果 l == r,必須 l++,r–,否則會出現棧溢位
if (l == r){
l++;
r–;
}
//向左遞迴
if (left quickSort(arr,left,r);
}

//向右遞迴
if (right > l){
quickSort(arr,l,right);
}
}
}

二、歸併排序
1.基本介紹
歸併排序(Merge sort)是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序

在交換過程中,2 個元素如果大小相等也沒有任何操作交換,這不會破壞穩定性。合併過程中我們可以令相同的元素本來在前的還保持在前,這樣就保證了相對順序沒有改變,因此歸併排序也是穩定的排序演算法

演算法步驟

申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合併後的序列
設定兩個指標,最初位置分別為兩個已經排序序列的起始位置
比較兩個指標所指向的元素,選擇相對小的元素放入到合併空間,並移動指標到下一位置
重複步驟 3 直到某一指標達到序列尾
將另一序列剩下的所有元素直接複製到合併序列尾

2.程式碼實現
package com.sisyphus.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;


public class MergeSort {
public static void main(String[] args) {
//int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
(“歸併排序後” + Arrays.toString(arr));

 //建立一個 80000 個隨機數的陣列
 int[] arr = new int[80000];
 for (int i = 0; i 

}

//分 + 合的方法
public static void mergeSort(int[] arr, int left, int right, int[] temp){
if (left int mid = (left + right) / 2;//中間索引
//向左遞迴進行分解
mergeSort(arr, left, mid, temp);
//向右遞迴進行分解
mergeSort(arr, mid+1,right,temp);
//合併
merge(arr, left, mid, right, temp);
}
}

//合併的方法


public static void merge(int[] arr, int left, int mid, int right, int[] temp){
int i = left; //初始化 i,左端有序序列的初始索引
int j = mid + 1;//初始化 j,右端有序序列的初始索引
int t = 0; //指向 temp 陣列的當前索引

//(一)
//先把左右兩邊(有序)的資料按照規則填充到 temp 陣列
//直到左右兩邊的有序序列有一邊處理完畢
while((i //如果左邊的有序序列的當前元素小於等於右邊有序序列的當前元素
//將左邊的當前元素複製到 temp 陣列
//然後 t 後移,i 後移
if (arr[i] temp[t] = arr[i];
t++;
i++;
}else{//反之,將右邊的當前元素複製到 temp 陣列
temp[t] = arr[j];
t++;
j++;
}
}

//(二)
//有剩餘資料的一邊,把其中的資料依次全部填充到 temp
while(i temp[t] = arr[i];
t++;
i++;
}
while(j temp[t] = arr[j];
t++;
j++;
}

//(三)
//將 temp 陣列的元素複製到 arr
//注意:並不是每次都複製所有資料
t = 0;
int tempLeft = left;//
//第一次合併時 tempLeft = 0,right = 1 第二次合併時 tempLeft = 2,right = 3 第三次合併時 tempLeft = 0,right = 3
//最後一次 tempLeft = 0,right = 7
(“tempLeft=”+tempLeft+" right="+right);
while(tempLeft arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
}

三、基數排序
1.基本介紹
基數排序(Radix Sort)是一種非比較型整數排序演算法,其原理是將整數按位數切割成不同的數字,然後按每個位數分別比較。由於整數也可以表達字串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是隻能使用於整數

基數排序基於分別排序,分別收集,因此是穩定的排序演算法

演算法步驟

將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零
從最低位開始,依次進行一次排序
從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列
計數排序、桶排序和基數排序都利用了桶的概念,但對桶的使用方法上有明顯差異:

桶排序:每個桶儲存一定範圍的數值
計數排序:每個桶只儲存單一鍵值
基數排序:根據鍵值的每位數字來分配桶

2.程式碼實現
package com.sisyphus.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;


public class RadixSort {
public static void main(String[] args) {
//int[] arr = {53, 3, 542, 748, 14, 214};

 //建立一個 80000 個隨機數的陣列
 int[] arr = new int[80000];
 for (int i = 0; i 

}

public static void radixSort(int[] arr){

 //1.得到陣列中最大的位數
 int max = arr[0];//假設第一個數就是最大數
 for (int i = 1; i  max){
         max = arr[i];
     }
 }
 //得到最大數是幾位數
 int maxLength = (max + "").length();

 //定義一個二維陣列,表示 10 個桶,每個桶就是一個一維陣列
 //說明
 //1.二維陣列包含 10 個一維陣列
 //2.為了防止在放入資料的時候溢位,設定每個一維陣列的大小為 arr.length
 //3.由此可見,基數排序是一種以空間換時間的演算法
 int[][] bucket = new int[10][arr.length];

 //為了記錄每個桶中,實際存放了多少個資料,我們定義一個一維陣列來記錄各個桶的每次放入的資料個數
 //可以這樣理解
 //比如:bucketElementCounts[0],記錄的就是 bucket[0] 桶的放入資料的個數
 int[] bucketElementCounts = new int[10];

 for (int i = 0, n = 1; i 

}
}

————————————————
版權宣告:本文為CSDN博主「313YPHU3」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/qq_45593575/article/details/118880356

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1795/viewspace-2797037/,如需轉載,請註明出處,否則將追究法律責任。

相關文章