Java實(shí)現(xiàn)十個(gè)經(jīng)典排序算法(帶動(dòng)態(tài)效果圖)

代碼模板

/**

* 希爾排序

* @param array

*/

public static void shellSort(int[] array){

? ? int len = array.length;

? ? int temp, gap = len / 2;

? ? while (gap > 0) {

? ? ? ? for (int i = gap; i < len; i++) {

? ? ? ? ? ? temp = array[i];

? ? ? ? ? ? int preIndex = i - gap;

? ? ? ? ? ? while (preIndex >= 0 && array[preIndex] > temp) {

? ? ? ? ? ? ? ? array[preIndex + gap] = array[preIndex];

? ? ? ? ? ? ? ? preIndex -= gap;

? ? ? ? ? ? }

? ? ? ? ? ? array[preIndex + gap] = temp;

? ? ? ? }

? ? ? ? gap /= 2;

? ? }

}

歸并排序

歸并排序是采用的分而治之的遞歸方式來完成數(shù)據(jù)排序的瓜贾,主要是將已有序的兩個(gè)子序列驾荣,合并成一個(gè)新的有序子序列景埃。先將子序列分段有序,然后再將分段后的子序列合并成今膊,最終完成數(shù)據(jù)的排序。

主要步驟:

將數(shù)據(jù)的長度從中間一分為二歉甚,分成兩個(gè)子序列万细,執(zhí)行遞歸操作,直到每個(gè)子序列就剩兩個(gè)元素纸泄。

然后分別對這些拆好的子序列進(jìn)行歸并排序赖钞。

將排序好的子序列再兩兩合并,最終合并成一個(gè)完整的排序序列聘裁。

動(dòng)圖演示

歸并排序

代碼模板

/**

? ? * 歸并排序

? ? * @param array? ? 數(shù)組

? ? * @param left? ? ? 0

? ? * @param right? ? array.length-1

? ? */

? ? public static void mergeSort(int[] array,int left,int right){


? ? ? ? if (right <= left){

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? // 一分為二

? ? ? ? int mid = (left + right)/2;

? ? ? ? // 對前半部分執(zhí)行歸并排序

? ? ? ? mergeSort(array, left, mid);

? ? ? ? // 對后半部分執(zhí)行歸并排序

? ? ? ? mergeSort(array, mid + 1, right);

? ? ? ? // 將分好的每個(gè)子序列雪营,執(zhí)行排序加合并操作

? ? ? ? merge(array, left, mid, right);

? ? }

? ? /**

? ? * 合并加排序

? ? * @param array

? ? * @param left

? ? * @param middle

? ? * @param right

? ? */

? ? public static void merge(int[] array,int left,int middle,int right){

? ? // 中間數(shù)組

? ? int[] temp = new int[right - left + 1];

? ? int i = left, j = middle + 1, k = 0;

? ? while (i <= middle && j <= right) {

? ? ? ? // 若前面數(shù)組的元素小,就將前面元素的數(shù)據(jù)放到中間數(shù)組中

? ? ? ? if(array[i] <= array[j]){

? ? ? ? ? ? temp[k++] = array[i++];

? ? ? ? }else {

? ? ? ? ? ? // 若后面數(shù)組的元素小衡便,就將后面數(shù)組的元素放到中間數(shù)組中

? ? ? ? ? ? temp[k++] = array[j++];

? ? ? ? }

? ? }

? ? // 若經(jīng)過上面的比較合并后献起,前半部分的數(shù)組還有數(shù)據(jù),則直接插入中間數(shù)組后面

? ? while (i <= middle){

? ? ? ? temp[k++] = array[i++];

? ? }

? ? // 若經(jīng)過上面的比較合并后镣陕,后半部分的數(shù)組還有數(shù)據(jù)谴餐,則直接插入中間數(shù)組后面

? ? while (j <= right){

? ? ? ? temp[k++] = array[j++];

? ? }

? ? // 將數(shù)據(jù)從中間數(shù)組中復(fù)制回原數(shù)組

? ? for (int p = 0; p < temp.length; p++) {

? ? ? ? array[left + p] = temp[p];

? ? }

}

歸并排序總結(jié)

歸并排序效率很高,時(shí)間復(fù)雜度能達(dá)到O(nlogn)呆抑,但是依賴額外的內(nèi)存空間岂嗓,而且這種分而治之的思想很值得借鑒,很多場景都是通過簡單的功能鹊碍,組成了復(fù)雜的邏輯厌殉,所以只要找到可拆分的最小單元食绿,就可以進(jìn)行分而治之了。

快速排序

快速排序公罕,和二分查找的思想很像器紧,都是先將數(shù)據(jù)一份為二然后再逐個(gè)處理÷ゾ欤快速排序也是最常見的排序算法的一種铲汪,面試被問到的概率還是比較大的。

主要步驟:

從數(shù)據(jù)中挑選出一個(gè)元素罐柳,稱為 "基準(zhǔn)"(pivot)桥状,一般選第一個(gè)元素或最后一個(gè)元素。

然后將數(shù)據(jù)中硝清,所有比基準(zhǔn)元素小的都放到基準(zhǔn)元素左邊辅斟,所有比基準(zhǔn)元素大的都放到基準(zhǔn)元素右邊。

然后再將基準(zhǔn)元素前面的數(shù)據(jù)集合和后面的數(shù)據(jù)集合重復(fù)執(zhí)行前面兩步驟芦拿。

動(dòng)圖演示

快速排序

代碼模板

/**

* 快速排序

* @param array 數(shù)組

* @param begin 0

* @param end? array.length-1

*/

public static void quickSort(int[] array, int begin, int end) {

? ? if (end <= begin) return;

? ? int pivot = partition(array, begin, end);

? ? quickSort(array, begin, pivot - 1);

? ? quickSort(array, pivot + 1, end);

}

/**

* 分區(qū)

* @param array

* @param begin

* @param end

* @return

*/

public static int partition(int[] array, int begin, int end) {

? ? // pivot: 標(biāo)桿位置士飒,counter: 小于pivot的元素的個(gè)數(shù)

? ? int pivot = end, counter = begin;

? ? for (int i = begin; i < end; i++) {

? ? ? ? if (array[i] < array[pivot]) {

? ? ? ? ? // 替換,將小于標(biāo)桿位置的數(shù)據(jù)放到開始位置算起小于標(biāo)桿數(shù)據(jù)的第counter位

? ? ? ? ? ? int temp = array[counter];

? ? ? ? ? ? array[counter] = array[i];

? ? ? ? ? ? array[i] = temp;

? ? ? ? ? ? counter++;

? ? ? ? }

? ? }

? ? // 將標(biāo)桿位置的數(shù)據(jù)移動(dòng)到小于標(biāo)桿位置數(shù)據(jù)的下一個(gè)位蔗崎。

? ? int temp = array[pivot];

? ? array[pivot] = array[counter];

? ? array[counter] = temp;

? ? return counter;

}

快速排序總結(jié)

我找的快速排序的模板代碼酵幕,是比較巧妙的,選擇了最后一個(gè)元素作為了基準(zhǔn)元素缓苛,然后小于基準(zhǔn)元素的數(shù)量芳撒,就是基準(zhǔn)元素應(yīng)該在的位置。這樣看起來是有點(diǎn)不好懂未桥,但是看明白之后笔刹,就會(huì)覺得這個(gè)模板寫的還是比較有意思的。

堆排序

堆排序其實(shí)是采用的堆這種數(shù)據(jù)結(jié)構(gòu)來完成的排序冬耿,一般堆排序的方式都是采用的一種近似完全二叉樹來實(shí)現(xiàn)的堆的方式完成排序舌菜,但是堆的實(shí)現(xiàn)方式其實(shí)不止有用二叉樹的方式,其實(shí)還有斐波那契堆亦镶。

而根據(jù)排序的方向又分為大頂堆和小頂堆:

大頂堆:每個(gè)節(jié)點(diǎn)值都大于或等于子節(jié)點(diǎn)的值日月,在堆排序中用做升序排序。

小頂堆:每個(gè)節(jié)點(diǎn)值都小于或等于子節(jié)點(diǎn)的值缤骨,在堆排序中用做降序排序爱咬。

像Java中的PriorityQueue就是小頂堆。

主要步驟:

創(chuàng)建一個(gè)二叉堆绊起,參數(shù)就是無序序列[0~n]精拟;

把堆頂元素和堆尾元素互換;

調(diào)整后的堆頂元素,可能不是最大或最小的值串前,所以還需要調(diào)整此時(shí)堆頂元素的到正確的位置,這個(gè)調(diào)整位置的過程实蔽,主要是和二叉樹的子元素的值對比后找到正確的位置荡碾。

重復(fù)步驟2、步驟3局装,直至整個(gè)序列的元素都在二叉堆的正確位置上了坛吁。

動(dòng)圖演示

堆排序

模板代碼

/**

* 堆排序

* @param array

*/

public static int[] heapSort(int[] array){

? ? int size = array.length;

? ? // 先將數(shù)據(jù)放入堆中

? ? for (int i = (int) Math.floor(size / 2); i >= 0; i--) {

? ? ? ? heapTopMove(array, i, size);

? ? }

? ? // 堆頂位置調(diào)整

? ? for(int i = size - 1; i > 0; i--) {

? ? ? ? swapNum(array, 0, i);

? ? ? ? size--;

? ? ? ? heapTopMove(array, 0,size);

? ? }

? ? return array;

}

/**

* 堆頂位置維護(hù)

* @param array

* @param i

* @param size

*/

public static void heapTopMove(int[] array,int i,int size){

? ? int left = 2 * i + 1;

? ? int right = 2 * i + 2;

? ? int largest = i;

? ? if (left < size && array[left] > array[largest]) {

? ? ? ? largest = left;

? ? }

? ? if (right < size && array[right] > array[largest]) {

? ? ? ? largest = right;

? ? }

? ? if (largest != i) {

? ? ? ? swapNum(array, i, largest);

? ? ? ? heapTopMove(array, largest, size);

? ? }

}

/**

* 比較交換

* @param array

* @param left

* @param right

*/

public static void swapNum(int[] array,int left,int right){

? ? int temp = array[left];

? ? array[left] = array[right];

? ? array[right] = temp;

}

堆排序總結(jié)

堆排序的時(shí)間復(fù)雜度也是O(nlogn),這個(gè)也是有一定的概率在面試中被考察到,其實(shí)如果真實(shí)在面試中遇到后铐尚,可以在實(shí)現(xiàn)上不用自己去維護(hù)一個(gè)堆拨脉,而是用Java中的PriorityQueue來實(shí)現(xiàn),可以將無序數(shù)據(jù)集合放入到PriorityQueue中宣增,然后再依次取出堆頂數(shù)據(jù)玫膀,取出堆頂數(shù)據(jù)時(shí)要從堆中移除取出的這個(gè)元素,這樣每次取出的就都是現(xiàn)有數(shù)據(jù)中最小的元素了爹脾。

計(jì)數(shù)排序

計(jì)數(shù)排序是一種線性時(shí)間復(fù)雜度的排序算法帖旨,它主要的邏輯時(shí)將數(shù)據(jù)轉(zhuǎn)化為鍵存儲(chǔ)在額外的數(shù)組空間里。計(jì)數(shù)排序有一定的局限性灵妨,它要求輸入的數(shù)據(jù)解阅,必須是有確定范圍的整數(shù)序列。

主要步驟:

找出待排序的數(shù)組中最大和最小的元素泌霍;

統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù)货抄,存入數(shù)組C的第i項(xiàng);

對所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開始朱转,每一項(xiàng)和前一項(xiàng)相加)蟹地;

反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1藤为。

動(dòng)圖演示

計(jì)數(shù)排序

代碼模板

/**

* 計(jì)數(shù)排序

* @param array

*/

public static void countSort(int[] array){

? ? int bucketLen = getMaxValue(array) + 1;

? ? int[] bucket = new int[bucketLen];

? ? // 統(tǒng)計(jì)每個(gè)值出現(xiàn)的次數(shù)

? ? for (int value : array) {

? ? ? ? bucket[value]++;

? ? }

? ? // 反向填充數(shù)組

? ? int sortedIndex = 0;

? ? for (int j = 0; j < bucketLen; j++) {

? ? ? ? while (bucket[j] > 0) {

? ? ? ? ? ? array[sortedIndex++] = j;

? ? ? ? ? ? bucket[j]--;

? ? ? ? }

? ? }

}

/**

* 獲取最大值

* @param arr

* @return

*/

private static int getMaxValue(int[] arr) {

? ? int maxValue = arr[0];

? ? for (int value : arr) {

? ? ? ? if (maxValue < value) {

? ? ? ? ? ? maxValue = value;

? ? ? ? }

? ? }

? ? return maxValue;

}

桶排序

桶排序算是計(jì)數(shù)排序的一個(gè)加強(qiáng)版锈津,它利用特定函數(shù)的映射關(guān)系,將屬于一定范圍內(nèi)的數(shù)據(jù)凉蜂,放到一個(gè)桶里琼梆,然后對每個(gè)桶中的數(shù)據(jù)進(jìn)行排序,最后再將排序好的數(shù)據(jù)拼接起來窿吩。

主要步驟:

設(shè)置一個(gè)合適長度的數(shù)組作為空桶茎杂;

遍歷數(shù)據(jù),將數(shù)據(jù)都放到指定的桶中纫雁,分布的越均勻越好煌往;

對每個(gè)非空的桶里的數(shù)據(jù)進(jìn)行排序;

將每個(gè)桶中排序好的數(shù)據(jù)拼接在一起。

動(dòng)圖演示

桶排序

代碼模板

/**

? * 桶排序

? * @param arr

? * @param bucketSize

? * @return

? */

private static int[] bucketSort(int[] arr, int bucketSize){

? ? if (arr.length == 0) {

? ? ? ? return arr;

? ? }

? ? int minValue = arr[0];

? ? int maxValue = arr[0];

? ? // 計(jì)算出最大值和最小值

? ? for (int value : arr) {

? ? ? ? if (value < minValue) {

? ? ? ? ? ? minValue = value;

? ? ? ? } else if (value > maxValue) {

? ? ? ? ? ? maxValue = value;

? ? ? ? }

? ? }

? ? // 根據(jù)桶的長度以及數(shù)據(jù)的最大值和最小值刽脖,計(jì)算出桶的數(shù)量

? ? int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;

? ? int[][] buckets = new int[bucketCount][0];

? ? // 利用映射函數(shù)將數(shù)據(jù)分配到各個(gè)桶中

? ? for (int i = 0; i < arr.length; i++) {

? ? ? ? int index = (int) Math.floor((arr[i] - minValue) / bucketSize);

? ? ? ? // 將數(shù)據(jù)填充到指定的桶中

? ? ? ? buckets[index] = appendBucket(buckets[index], arr[i]);

? ? }

? ? int arrIndex = 0;

? ? for (int[] bucket : buckets) {

? ? ? ? if (bucket.length <= 0) {

? ? ? ? ? ? continue;

? ? ? ? }

? ? ? ? // 對每個(gè)桶進(jìn)行排序羞海,這里使用了插入排序

? ? ? ? InsertSort.insertSort(bucket);

? ? ? ? for (int value : bucket) {

? ? ? ? ? ? arr[arrIndex++] = value;

? ? ? ? }

? ? }

? ? return arr;

}

/**

? * 擴(kuò)容,并追加數(shù)據(jù)

? *

? * @param array

? * @param value

? */

private static int[] appendBucket(int[] array, int value) {

? ? array = Arrays.copyOf(array, array.length + 1);

? ? array[array.length - 1] = value;

? ? return array;

}

USB Microphone https://www.soft-voice.com/

Wooden Speakers? https://www.zeshuiplatform.com/

亞馬遜測評 www.yisuping.cn

深圳網(wǎng)站建設(shè)www.sz886.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末曲管,一起剝皮案震驚了整個(gè)濱河市却邓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌院水,老刑警劉巖腊徙,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異檬某,居然都是意外死亡撬腾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門恢恼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來民傻,“玉大人,你說我怎么就攤上這事场斑∈吻保” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵和簸,是天一觀的道長彭雾。 經(jīng)常有香客問我,道長锁保,這世上最難降的妖魔是什么薯酝? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮爽柒,結(jié)果婚禮上吴菠,老公的妹妹穿的比我還像新娘。我一直安慰自己浩村,他們只是感情好做葵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著心墅,像睡著了一般酿矢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怎燥,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天瘫筐,我揣著相機(jī)與錄音,去河邊找鬼铐姚。 笑死策肝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播之众,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拙毫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了棺禾?” 一聲冷哼從身側(cè)響起缀蹄,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帘睦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坦康,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡竣付,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滞欠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片古胆。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖筛璧,靈堂內(nèi)的尸體忽然破棺而出逸绎,到底是詐尸還是另有隱情,我是刑警寧澤夭谤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布棺牧,位于F島的核電站,受9級特大地震影響朗儒,放射性物質(zhì)發(fā)生泄漏颊乘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一醉锄、第九天 我趴在偏房一處隱蔽的房頂上張望乏悄。 院中可真熱鬧,春花似錦恳不、人聲如沸檩小。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽规求。三九已至,卻和暖如春卵惦,著一層夾襖步出監(jiān)牢的瞬間颓哮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工鸵荠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冕茅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像姨伤,于是被迫代替她去往敵國和親哨坪。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容