单链表实现快速排序
用單鏈表實(shí)現(xiàn)快速排序
前言:快速排序我們都知道,通過(guò)一個(gè)基準(zhǔn)數(shù)字,一趟排序就將數(shù)據(jù)劃分為兩個(gè)部分:左邊的部分小于這個(gè)基準(zhǔn)數(shù)字,右邊的部分大于等于這個(gè)基準(zhǔn)數(shù)字。我們知道,實(shí)現(xiàn)快速排序的關(guān)鍵在于隨機(jī)訪問數(shù)據(jù)元素,所以以往的快排都是基于數(shù)組實(shí)現(xiàn)的。但是在面試中,經(jīng)常會(huì)遇到面試官要求我們用鏈表實(shí)現(xiàn)快排,那么如何通過(guò)鏈表實(shí)現(xiàn)快排呢?
我們?cè)O(shè)置兩個(gè)指針 i,j,其中 i 初始時(shí)指向數(shù)組的第一個(gè)元素,j 初始化為 i+1。?
然后,我們?cè)O(shè)定 i 指向的元素為基準(zhǔn)數(shù)字。
我們要做的事情,就是在一趟排序中,把那些比基準(zhǔn)數(shù)字小的數(shù),移動(dòng)到前面。?
具體的算法如下:
如果 j 指向的值大于等于基準(zhǔn)數(shù)字(如果比基準(zhǔn)大,直接跳過(guò))?
j ++
如果 j 指向的值小于基準(zhǔn)數(shù)字,(如果比基準(zhǔn)小,交換 i 和 j 位置的值)?
i ++
swap(i, j)
j ++
以【4,2,5,3,7,9,0,1】為例,我們來(lái)模擬一趟快排的過(guò)程。
1、初始化時(shí),i指向鏈表首元素4;j = i +1,指向2。基準(zhǔn)數(shù)字為當(dāng)前i 指向的數(shù)字:4。
j?? ??? ??? ??? ??? ??? ?
4?? ?2?? ?5?? ?3?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ??? ??? ?
2、隨后開始循環(huán),j 當(dāng)前指向2,因?yàn)?小于4,所以要把2移動(dòng)到前面去。按照我們的算法步驟操作:
i ++,首先 i 向后移動(dòng)一位,指向2
swap(i, j) ,隨后交換 i、j 位置的值,這里面是2和2自己交換
j ++,然后 j 向后移動(dòng)一位,指向5
執(zhí)行一次交換后的結(jié)果如下:
j?? ??? ??? ??? ??? ?
4?? ?2?? ?5?? ?3?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ??? ?
3、接下來(lái),由于 j 指向的值5 大于4,直接跳過(guò),執(zhí)行j++,此時(shí) j 指向3
j?? ??? ??? ??? ?
4?? ?2?? ?5?? ?3?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ??? ?
4、 j 指向的值為3,小于4,仿照步驟2,我們?cè)俅螆?zhí)行一次交換移動(dòng)過(guò)程。
i ++,首先 i 向后移動(dòng)一位,指向5
swap(i, j) ,隨后交換 i、j 位置的值,這里面是5和3交換
j ++,然后 j 向后移動(dòng)一位,指向7
交換后的結(jié)果如下:
j?? ??? ??? ?
4?? ?2?? ?3?? ?5?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ?
5、 j指向的值為7,大于4,所以直接跳過(guò),執(zhí)行 j++,j 指向9
j?? ??? ?
4?? ?2?? ?3?? ?5?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ?
6、同理,j 指向的值為9,也大于4,跳過(guò),執(zhí)行 j++,j 指向0
j?? ?
4?? ?2?? ?3?? ?5?? ?7?? ?9?? ?0?? ?1
i?? ??? ??? ??? ??? ?
7、 j 指向的值為0,小于4,執(zhí)行一次交換過(guò)程
i ++,首先 i 向后移動(dòng)一位,指向5
swap(i, j) ,隨后交換 i、j 位置的值,這里面是5和0交換
j ++,然后 j 向后移動(dòng)一位,指向1
交換后的結(jié)果如下:
j
4?? ?2?? ?3?? ?0?? ?7?? ?9?? ?5?? ?1
i?? ??? ??? ??? ?
8、 j 指向的值為1,小于4,我們?cè)賵?zhí)行一次交換過(guò)程
i ++,首先 i 向后移動(dòng)一位,指向7
swap(i, j) ,隨后交換 i、j 位置的值,這里面是7和1交換
j ++,然后 j 向后移動(dòng)一位,已經(jīng)超過(guò)了鏈表的長(zhǎng)度,不再向后移動(dòng)。
交換后的結(jié)果如下:
j
4?? ?2?? ?3?? ?0?? ?1?? ?9?? ?5?? ?7?? ?
i?? ??? ??? ??? ?
9、最后,交換當(dāng)前 i指向的值1,和4。得到【1、2、3、0、4、9、5、7】,一趟排序結(jié)束。
j
1?? ?2?? ?3?? ?0?? ?4?? ?9?? ?5?? ?7?? ?
i?? ??? ??? ??? ?
我們發(fā)現(xiàn),4的左邊都是小于4的數(shù)字,右邊都是大于4的數(shù)字。?
接下來(lái),對(duì)左邊和右邊分別排序,不斷遞歸下去,直到元素全部有序。
在交換的時(shí)候,為什么要讓i先向后移動(dòng)呢?
這是因?yàn)?#xff0c;在整個(gè)排序的過(guò)程中,i 前面指向的都是小于4的數(shù)字,i 后面指向的都是大于4的數(shù)字,i 是左右兩邊的分界線。我們交換的目的是把小于4的交換到前面,把大于4的交換到后面,所以 i 要先向后移動(dòng)1位,找到后面第一個(gè)大于4的數(shù),然后把這個(gè)大于4的數(shù),和后面小于4的數(shù)交換。
以上算法的 java 代碼如下:
import java.util.*;
public class Main{
? ? // 交換
? ? public static void swap(LinkedList<Integer> list, int i, int j) {
? ? ? ? int t = list.get(j);
? ? ? ? list.set(j, list.get(i));
? ? ? ? list.set(i, t);
? ? }
? ? public static void qsort(LinkedList<Integer> list, int left, int right) {
? ? ? ? if(left < right) {
? ? ? ? ? ? int i = left; // 初始化i,為鏈表第一個(gè)元素(最左邊的元素)
? ? ? ? ? ? int j = i + 1; // 初始化j = i + 1
? ? ? ? ? ? int x = list.get(i); // 基準(zhǔn)數(shù)字
? ? ? ? ? ? while(j <= right) { // 大循環(huán)條件,j不能超過(guò)鏈表長(zhǎng)度
? ? ? ? ? ? ? ? // 如果 j 指向的值大于等于基準(zhǔn)數(shù)字(如果比基準(zhǔn)大,直接跳過(guò))
? ? ? ? ? ? ? ? while(j <= right && list.get(j) >= x) j++;
? ? ? ? ? ? ? ? // 否則,j 指向的值小于基準(zhǔn),則交換
? ? ? ? ? ? ? ? if(j <= right) {
? ? ? ? ? ? ? ? ? ? i++; // 交換時(shí),i 首先要向后移動(dòng)一位
? ? ? ? ? ? ? ? ? ? swap(list, i, j); // 交換
? ? ? ? ? ? ? ? ? ? j++; // 隨后,j向后移動(dòng)一位
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }?
? ? ? ? ? ? swap(list, left, i); // 最后,交換 i 位置的值和基準(zhǔn)元素。一趟排序結(jié)束。
? ? ? ? ? ? qsort(list, left, i-1); ? // 遞歸排序左邊
? ? ? ? ? ? qsort(list, i+1, right); ?// 遞歸排序右邊
? ? ? ? }
? ? }
? ? public static void main(String[] args) {
? ? ? ? LinkedList<Integer> list = new LinkedList();
? ? ? ? int[] arr = {4,2,5,3,7,9,0,1}; // test case 1
// ? ? ?int[] arr = {5,4,3,2,1,6,7,9,8,10}; // test case 2
? ? ? ? for(int i = 0; i < arr.length; i++) {
? ? ? ? ? ? list.add(arr[i]);
? ? ? ? }
? ? ? ? qsort(list, 0, arr.length-1);
? ? ? ? System.out.println(list.toString());
? ? }
}
?
總結(jié)
- 上一篇: 线程安全的强弱级别
- 下一篇: 网络:HTTP1.1和HTTP2区别