排序算法名稱 | 針對的應用情景 |
---|---|
快速排序 | 無序素組(對于基本有序數組和大量重復鍵值的數組復雜度上升至O(n2) |
隨機速排 | 快速排序的優化,解決普通快排在部分有序數組中進行排序,每次取得的都是趨近最值 |
二路快排 | 隨機速排的優化,解決數組中存在大量鍵值重復的情況以及基本有序數組 |
三路快排 | 二路排序的優化,把等于value的元素放在另一個區間內,不參與下次的排序。 |
從上到下都是基于上面的排序算法進行優化
swap方法原型
/**
* 沒有辦法想C語言的指針那樣直接通過指針交換,可以通過數組或者是對象屬性來交換
* @param arr 數組名
* @param x 下標
* @param y 下標
*/
public static void swap(int[] arr, int x, int y){
int temp;
temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
Java快速排序
ackage sort;
import org.junit.Test;
import static sort.PublicMethod.swap;
/**
* @author panghu
* @title: QuickSort
* @projectName Algorithm_And_Data_Structure
* @date 19-6-5 下午8:05
*/
public class QuickSort {
private void quickSort(int[] arr, int l, int r) {
if (l >= r){
return;
}
int position = partition(arr,l,r);
quickSort(arr,l,position-1);
quickSort(arr,position+1,r);
}
/*
* 對arr[l...r]部分進行partition操作
* 返回position,是的arr[l...p-1]<arr[p],arr[p+1...r]>arr[p]
* */
public static int partition(int[] arr,int left,int right){
int value = arr[left];
int position = left;
//這里的right值是最右邊的值 arr[right]是有效的
for (int i=left+1;i<=right;i++){
if (arr[i] < value){
/*
* 相關的操作
* 1.比初始位置大的數都放在初始位置的右邊一個,放一個position的位置增加一
* */
swap(arr,i,++position);
}
}
//走到這一步的時候 arr[l]存放的是分解值,arr[position]存放的是小于分界值
swap(arr,left,position);
return position;
}
@Test
public void test(){
int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
quickSort(a, 0,a.length-1);
System.err.println("排好序的數組:");
for (int e : a) {
System.out.print(e+" ");
}
}
}
快速排序算法
思路:
- 從序列中挑選出一個元素(一般是第一個或者是最后一個)作為"基準"元素
- 把序列分成2個部分,其數值大于"基準"元素的元素放在"基準"元素的左邊,否在放在"基準"元
素的右邊,此時"基準"元素所在的位置就是正確的排序位置,這個過程被稱為 partition(分區) - 遞歸將"基準"元素左邊的序列和"基準"元素右邊的序列進行partition操作
缺點:
- 當partition操作時,如果每次取得的的第一個元素趨近于最值,使得分治的任務極度不平衡,情況最壞時,快速排序算法的復雜度將上升到O(n2)**
- 存在大量重復鍵值時,同樣會出現分治任務很不平衡的情況
隨機快速排序算法
package sort;
import org.junit.Test;
import static sort.PublicMethod.swap;
/**
* @author panghu
* @title: RandomQuickSort
* @projectName Algorithm_And_Data_Structure
* @date 19-7-21 下午9:49
*/
public class RandomQuickSort {
private void quickSort(int[] arr, int l, int r) {
if (l >= r){
return;
}
int position = partition(arr,l,r);
quickSort(arr,l,position-1);
quickSort(arr,position+1,r);
}
/*
* 對arr[l...r]部分進行partition操作
* 返回position,是的arr[l...p-1]<arr[p],arr[p+1...r]>arr[p]
* */
public static int partition(int[] arr,int left,int right){
int value = arr[left];
//這個地方是唯一的區別.在left~right之間生成一個隨機數
int ranNum = left + (int)(Math.random()*(right-left+1));
//把隨機數作為索引,將索引對應值與最后一位值 right 交換
swap(arr,right,ranNum);
int position = left;
//這里的right值是最右邊的值 arr[right]是有效的
for (int i=left+1;i<=right;i++){
if (arr[i] < value){
/*
* 相關的操作
* 1.比初始位置大的數都放在初始位置的右邊一個,放一個position的位置增加一
* */
swap(arr,i,++position);
}
}
//走到這一步的時候 arr[l]存放的是分解值,arr[position]存放的是小于分界值
//自我感覺這一步 有一種一舉兩得,即將分界值的位置移到了正確位置,也將左值放在了左邊
swap(arr,left,position);
return position;
}
@Test
public void test(){
int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
quickSort(a, 0,a.length-1);
System.err.println("排好序的數組:");
for (int e : a) {
System.out.print(e+" ");
}
}
}
思路:
- 在每次partition的過程中,
將left
到right-1
之間的隨機選取一個元素,與right進行位置交換,這樣就解決了快排中如果數組部分有序,數組劃分不平衡的情況
缺點
- 當數組中存在大量重復鍵值的時候任然會出現算法復雜度上升的情況
兩路快速排序算法
package sort;
import org.junit.Test;
import static sort.PublicMethod.swap;
/**
* @author panghu
* @title: QuickSort2
* @projectName Algorithm_And_Data_Structure
* @date 19-7-22 下午10:27
*/
public class QuickSort2 {
private void quickSort(int[] arr, int l, int r) {
if (l >= r){
return;
}
int position = partition(arr,l,r);
quickSort(arr,l,position-1);
quickSort(arr,position+1,r);
}
int partition(int[] arr, int left, int right){
int ranNum = left + (int)(Math.random()*(right-left+1));
//把隨機數作為索引,將索引對應值與最后一位值 right 交換
swap(arr,right,ranNum);
// arr[left+1...i) <= v; arr(j...right] >= v
int value = arr[left];
int i = left+1, j = right;
while( true ){
while( i <= right && arr[i] < value) {
i ++;
}
while( j >= left+1 && arr[j] > value ) {
j --;
}
if( i > j ) {
break;
}
swap(arr,i,j);
i ++;
j --;
}
swap(arr, left, j);
return j;
}
@Test
public void test(){
int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
quickSort(a, 0,a.length-1);
System.err.println("排好序的數組:");
for (int e : a) {
System.out.print(e+" ");
}
}
}
二路快速排序
二路快速排序
思路:
- 從左邊和右邊分別遍歷,當左邊遍歷到第i位置時,所對應的元素大于v,從右邊遍歷的元素遍歷到第j個位置時,所對應的元素arr[j]<v,交換i和j的位置直到i>j.適用于有大量重復鍵值的情形和數組基本有序的問題
package sort;
import org.junit.Test;
import static sort.PublicMethod.swap;
/**
* @author panghu
* @title: QuickSort3
* @projectName Algorithm_And_Data_Structure
* @date 19-7-23 下午2:02
*/
public class QuickSort3 {
private void quickSort(int[] arr, int l, int r) {
if (l >= r){
return;
}
int position = partition(arr,l,r);
quickSort(arr,l,position-1);
quickSort(arr,position+1,r);
}
int partition(int[] arr,int left,int right){
int ranNum = left + (int)(Math.random()*(right-left+1));
//把隨機數作為索引,將索引對應值與最后一位值 right 交換
swap(arr,right,ranNum);
// arr[left+1...i) <= value; arr(j...right] >= value
int value = arr[left];
// 將<v的分界線的索引值lt初始化為第一個元素的位置(也就是<v部分的最后一個元素所在位置)
int lt = left;
//將>value的分界線的索引值gt初始化為最后一個元素right的后一個元素所在位置
// (也就是>value部分的第一個元素所在位置)
int gt = right+1;
// 將遍歷序列的索引值i初始化為 left+1
int i = left+1;
while (i < gt){
if (arr[i] < value){
swap(arr, lt+1, i);
//移動指針
i++;
//增加<value的部分
lt++;
}else if ( arr[i] > value){
swap(arr,gt-1,i);
//增加>value的部分
gt--;
//注意,這里不需要移動i,之前移動i是因為需要增加<value的部分
//而保持=i部分不懂,所以i和lt都需要移動
}else{
//增加=v的部分
i++;
}
}
return i;
}
@Test
public void test(){
int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
quickSort(a, 0,a.length-1);
System.err.println("排好序的數組:");
for (int e : a) {
System.out.print(e+" ");
}
}
}
三路快速排序算法
三路快速排序算法
三路快速排序算法
三路快速排序算法
三路快速排序算法
思路:
- 之前的快速排序是將數組劃分為 分成<=v和>v或者是<v和>=v的兩個部分,而三路快排是將數組劃分為分成三個部分:`<v、=v、>v
應用演示
package leetcode;
/**
* 題目要求:給定一個包含紅色、白色和藍色,一共 n 個元素的數組,原地對它們進行排序,
* 使得相同顏色的元素相鄰,并按照紅色、白色、藍色順序排列。
* 此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。
*/
import java.util.Arrays;
/**
* @author panghu
* @title: Solution75
* @projectName Algorithm_And_Data_Structure
* @date 19-7-16 下午10:06
*/
public class Solution75 {
**
* 三路快速排序法的應用
* @param nums 傳入的數組
*/
static void sortColors(int[] nums){
// nums[0...zero] == 0
int zero = -1;
// nums[two..n-1] == 2
int two = nums.length;
for (int i = 0;i < two;){
if (nums[i] == 1){
i++;
}else if (nums[i] == 2){
two--;
swap(nums,i,two);
}else {
if (nums[i] != 0){
throw new IllegalArgumentException("數組中的值只能為1,2,3");
}
zero++;
swap(nums,i,zero);
}
}
}
/**
* 通過數組交換數值
* @param arr 數組
* @param x 數組索引1
* @param y 數組索引2
*/
static void swap(int[] arr,int x,int y){
//temp用來臨時存儲值
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
public static void main(String[] args) {
int[] arr = {1,2,1,2,1,0,0,0,0,0};
sortColors(arr);
System.out.println(Arrays.toString(arr));
}
}
參考博客:https://www.cnblogs.com/deng-tao/p
參考課程:https://coding.imooc.com/class/chapter/71.html#Anchor