bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

Java編程怎么實現快速排序及優化

本篇內容主要講解“Java編程怎么實現快速排序及優化”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java編程怎么實現快速排序及優化”吧!

成都創新互聯主要業務有網站營銷策劃、網站建設、做網站、微信公眾號開發、小程序設計、成都h5網站建設、程序開發等業務。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當客戶,還把客戶視為我們的合作伙伴,在開展業務的過程中,公司還積累了豐富的行業經驗、全網整合營銷推廣資源和合作伙伴關系資源,并逐漸建立起規范的客戶服務和保障體系。 

普通快速排序

找一個基準值base,然后一趟排序后讓base左邊的數都小于base,base右邊的數都大于等于base。再分為兩個子數組的排序。如此遞歸下去。

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1);
	}
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
		if (left >= right) return;
		int p = partition(arr, left, right);
		sort(arr, left, p - 1);
		sort(arr, p + 1, right);
	}
	private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
		T base = arr[left];
		int j = left;
		for (int i = left + 1; i <= right; i++) {
			if (base.compareTo(arr[i]) > 0) {
				j++;
				swap(arr, j, i);
			}
		}
		swap(arr, left, j);
		return j;
		//返回一躺排序后基準值的下角標
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

快速排序優化:隨機選取基準值base

在數組幾乎有序時,快排性能不好(因為每趟排序后,左右兩個子遞歸規模相差懸殊,大的那部分最后很可能會達到O(n^2))。

解決:基準值隨機地選取,而不是每次都取第一個數。這樣就不會受“幾乎有序的數組”的干擾了。但是對“幾乎亂序的數組”的排序性能可能會稍微下降,至少多了排序前交換的那部分,亂序時這個交換沒有意義...有很多“運氣”成分..

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1);
	}
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right) {
		if (left >= right) return;
		int p = partition(arr, left, right);
		sort(arr, left, p - 1);
		sort(arr, p + 1, right);
	}
	private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
		//排序前,先讓基準值和隨機的一個數進行交換。這樣,基準值就有隨機性。
		//就不至于在數組相對有序時,導致左右兩邊的遞歸規模不一致,產生最壞時間復雜度
		swap(arr,left,(int)(Math.random()*(right - left + 1)+left));
		T base = arr[left];
		int j = left;
		for (int i = left + 1; i <= right; i++) {
			if (base.compareTo(arr[i]) > 0) {
				j++;
				swap(arr, j, i);
			}
		}
		swap(arr, left, j);
		return j;
		//返回一躺排序后,基準值的下角標
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

快速排序繼續優化:配合著使用插入排序

快排是不斷減小問題規模來解決子問題的,需要不斷遞歸。但是遞歸到規模足夠小時,如果繼續采用這種 不穩定+遞歸 的方式執行下去,效率不見得會很好。

所以當問題規模較小時,近乎有序時,插入排序表現的很好。Java自帶的Arrays.sort()里經常能看到這樣的注釋:“Use insertion sort on tiny arrays”,“Insertion sort on smallest arrays”

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1, 16);
	}
	/**
   * @param arr  待排序的數組
   * @param left 左閉
   * @param right 右閉
   * @param k   當快排遞歸到子問題的規模 <= k 時,采用插入排序優化
   * @param <T>  泛型,待排序可比較類型
   */
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right, int k) {
		// 規模小時采用插入排序
		if (right - left <= k) {
			insertionSort(arr, left, right);
			return;
		}
		int p = partition(arr, left, right);
		sort(arr, left, p - 1, k);
		sort(arr, p + 1, right, k);
	}
	public static <T extends Comparable<? super T>> void insertionSort(T[] arr, int l, int r) {
		for (int i = l + 1; i <= r; i++) {
			T cur = arr[i];
			int j = i - 1;
			for (; j >= 0 && cur.compareTo(arr[j]) < 0; j--) {
				arr[j + 1] = arr[j];
			}
			arr[j + 1] = cur;
		}
	}
	private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
		//排序前,先讓基準值和隨機的一個數進行交換。這樣,基準值就有隨機性。
		//就不至于在數組相對有序時,導致左右兩邊的遞歸規模不一致,產生最壞時間復雜度
		swap(arr, left, (int) (Math.random() * (right - left + 1) + left));
		T base = arr[left];
		int j = left;
		for (int i = left + 1; i <= right; i++) {
			if (base.compareTo(arr[i]) > 0) {
				j++;
				swap(arr, j, i);
			}
		}
		swap(arr, left, j);
		return j;
		//返回一躺排序后,基準值的下角標
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

快速排序繼續優化:兩路快排

在最開始的普通快速排序說過,讓基準值base左邊的都比base小,而base右邊的都大于等于base。等于base的這些會聚集到右側(或者稍微改改大小關系就會聚集到左側)。總之就會聚集到一邊。這樣在數組中重復數字很多的時候,就又會導致兩邊子遞歸規模差距懸殊的情況。這時想把等于base的那些數分派到base兩邊,而不是讓他們聚集到一起。

(注:測試代碼的時候,最好把插入排序那部分注視掉,向我下面代碼中那樣...不然數據量小于k=16的時候執行的是插入排序.....)

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1, 16);
	}
	/**
   * @param arr  待排序的數組
   * @param left 左閉
   * @param right 右閉
   * @param k   當快排遞歸到子問題的規模 <= k 時,采用插入排序優化
   * @param <T>  泛型,待排序可比較類型
   */
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right, int k) {
		// 規模小時采用插入排序
		//    if (right - left <= k) {
		//      insertionSort(arr, left, right);
		//      return;
		//    }
		if (left >= right) return;
		int p = partition(arr, left, right);
		sort(arr, left, p - 1, k);
		sort(arr, p + 1, right, k);
	}
	public static <T extends Comparable<? super T>> void insertionSort(T[] arr, int l, int r) {
		for (int i = l + 1; i <= r; i++) {
			T cur = arr[i];
			int j = i - 1;
			for (; j >= 0 && cur.compareTo(arr[j]) < 0; j--) {
				arr[j + 1] = arr[j];
			}
			arr[j + 1] = cur;
		}
	}
	private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
		//排序前,先讓基準值和隨機的一個數進行交換。這樣,基準值就有隨機性。
		//就不至于在數組相對有序時,導致左右兩邊的遞歸規模不一致,產生最壞時間復雜度
		swap(arr, left, (int) (Math.random() * (right - left + 1) + left));
		T base = arr[left];
		//基準值,每次都把這個基準值拋出去,看成[left+1.....right]左閉右閉區間的排序
		int i = left + 1;
		//對于上一行提到的[left+1.....right]區間,i表示 [left+1......i)左閉右開區間的值都小于等于base。
		int j = right;
		//對于上二行提到的[left+1.....right]區間,j表示 (j......right]左開右閉區間的值都大于等于base。
		while (true) {
			//從左到右掃描,掃描出第一個比base大的元素,然后i停在那里。
			while (i <= right && arr[i].compareTo(base) < 0) i++;
			//從右到左掃描,掃描出第一個比base小的元素,然后j停在那里。
			while (j >= left && arr[j].compareTo(base) > 0) j--;
			if (i > j) {
				//雖說是i>j,但其實都是以j=i-1為條件結束的
				break;
			}
			swap(arr, i++, j--);
		}
		swap(arr, left, j);
		return j;
		//返回一躺排序后,基準值的下角標
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

快速排序繼續優化:兩路快排 不用swap,用交換

上面的兩路在找到大于base的值和小于base的值時,用的是swap()方法來進行交換。兩數交換涉及到第三個變量temp的操作,多了讀寫操作。接下來用直接賦值的方法,把小于的放到右邊,大于的放到左邊,當i和j相遇時,那個位置就是base該放的地方。至此一趟完成。遞歸即可。

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1, 16);
	}
	/**
   * @param arr  待排序的數組
   * @param left 左閉
   * @param right 右閉
   * @param k   當快排遞歸到子問題的規模 <= k 時,采用插入排序優化
   * @param <T>  泛型,待排序可比較類型
   */
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right, int k) {
		// 規模小時采用插入排序
		//    if (right - left <= k) {
		//      insertionSort(arr, left, right);
		//      return;
		//    }
		if (left >= right) return;
		int p = partition(arr, left, right);
		sort(arr, left, p - 1, k);
		sort(arr, p + 1, right, k);
	}
	public static <T extends Comparable<? super T>> void insertionSort(T[] arr, int l, int r) {
		for (int i = l + 1; i <= r; i++) {
			T cur = arr[i];
			int j = i - 1;
			for (; j >= 0 && cur.compareTo(arr[j]) < 0; j--) {
				arr[j + 1] = arr[j];
			}
			arr[j + 1] = cur;
		}
	}
	private static <T extends Comparable<? super T>> int partition(T[] arr, int left, int right) {
		//排序前,先讓基準值和隨機的一個數進行交換。這樣,基準值就有隨機性。
		//就不至于在數組相對有序時,導致左右兩邊的遞歸規模不一致,產生最壞時間復雜度
		swap(arr, left, (int) (Math.random() * (right - left + 1) + left));
		T base = arr[left];
		//基準值,每次都把這個基準值拋出去,看成[left+1.....right]左閉右閉區間的排序
		int i = left;
		//對于上一行提到的[left+1.....right]區間,i表示 [left+1......i)左閉右開區間的值都小于等于base。
		int j = right;
		//對于上二行提到的[left+1.....right]區間,j表示 (j......right]左開右閉區間的值都大于等于base。
		while (i < j) {
			//從右到左掃描,掃描出第一個比base小的元素,然后j停在那里。
			while (j > i && arr[j].compareTo(base) > 0) j--;
			arr[i] = arr[j];
			//從左到右掃描,掃描出第一個比base大的元素,然后i停在那里。
			while (i < j && arr[i].compareTo(base) < 0) i++;
			arr[j] = arr[i];
		}
		arr[j] = base;
		return j;
		//返回一躺排序后,基準值的下角標
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

快速排序繼續優化:當大量數據,且重復數多時,用三路快排

把數組分為三路,第一路都比base小,第二路都等于base,第三路都大于base。

用指針從前到后掃描,如果:

1.cur指向的數小于base,那么:交換arr[cur]和arr[i]的值,然后i++,cur++。

2.cur指向的數等于base,那么:cur++

3.cur指向的數大于base,那么:交換arr[cur]和arr[j]的值,然后j--。

當cur>j的時候說明三路都已經完成。

Java編程怎么實現快速排序及優化

public class QuickSort {
	public static <T extends Comparable<? super T>> void sort(T[] arr) {
		sort(arr, 0, arr.length - 1, 16);
	}
	/**
   * @param arr  待排序的數組
   * @param left 左閉
   * @param right 右閉
   * @param k   當快排遞歸到子問題的規模 <= k 時,采用插入排序優化
   * @param <T>  泛型,待排序可比較類型
   */
	public static <T extends Comparable<? super T>> void sort(T[] arr, int left, int right, int k) {
		// 規模小時采用插入排序
		//    if (right - left <= k) {
		//      insertionSort(arr, left, right);
		//      return;
		//    }
		if (left >= right) return;
		int[] ret = partition(arr, left, right);
		sort(arr, left, ret[0], k);
		sort(arr, ret[1], right, k);
	}
	public static <T extends Comparable<? super T>> void insertionSort(T[] arr, int l, int r) {
		for (int i = l + 1; i <= r; i++) {
			T cur = arr[i];
			int j = i - 1;
			for (; j >= 0 && cur.compareTo(arr[j]) < 0; j--) {
				arr[j + 1] = arr[j];
			}
			arr[j + 1] = cur;
		}
	}
	/**
   * @param arr  待排序的數組
   * @param left 待排序數組的左邊界
   * @param right 待排序數組的右邊界
   * @param <T>  泛型
   * @return
   */
	private static <T extends Comparable<? super T>> int[] partition(T[] arr, int left, int right) {
		//排序前,先讓基準值和隨機的一個數進行交換。這樣,基準值就有隨機性。
		//就不至于在數組相對有序時,導致左右兩邊的遞歸規模不一致,產生最壞時間復雜度
		swap(arr, left, (int) (Math.random() * (right - left + 1) + left));
		T base = arr[left];
		//基準值,每次都把這個基準值拋出去,看成[left+1.....right]左閉右閉區間的排序
		//三路快排分為下面這三個路(區間)
		int i = left;
		// left表示,[lleft...left) 左閉右開區間里的數都比base小
		int j = right;
		// left表示,(rright...right] 左開右閉區間里的數都比base大
		int cur = i;
		//用cur來遍歷數組。[left...cur)左閉右開區間里的數都等于base
		while (cur <= j) {
			if (arr[cur].compareTo(base) == 0) {
				cur++;
			} else if (arr[cur].compareTo(base) < 0) {
				swap(arr, cur++, i++);
			} else {
				swap(arr, cur, j--);
			}
		}
		return new int[]{i - 1, j + 1};
		//[i...j]都等于base,子問題就只需要解決i左邊和j右邊就行了
	}
	public static void swap(Object[] arr, int i, int j) {
		if (i != j) {
			Object temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	private static void printArr(Object[] arr) {
		for (Object o : arr) {
			System.out.print(o);
			System.out.print("\t");
		}
		System.out.println();
	}
	public static void main(String args[]) {
		Integer[] arr = {3, 5, 1, 7, 2, 9, 8, 0, 4, 6};
		printArr(arr);
		//3  5  1  7  2  9  8  0  4  6
		sort(arr);
		printArr(arr);
		//0  1  2  3  4  5  6  7  8  9
	}
}

到此,相信大家對“Java編程怎么實現快速排序及優化”有了更深的了解,不妨來實際操作一番吧!這里是創新互聯網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

分享名稱:Java編程怎么實現快速排序及優化
鏈接URL:http://vcdvsql.cn/article12/peijdc.html

成都網站建設公司_創新互聯,為您提供搜索引擎優化Google營銷型網站建設小程序開發品牌網站設計服務器托管

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都網站建設