[算法天天见](二)进阶排序

xiaoxiao2025-10-25  10

进阶排序

一、说明二、算法归并排序快速排序

一、说明

进阶排序主要会展示归并排序算法和快速排序算法。归并排序算法由于不是原地排序算法所以它的空间复杂度不是O(1),它的时间复杂度是O(nlogn)。整个算法如果采用递归方式去写的话是很简单的,具体可参看代码部分。 快速排序的思路和归并排序是一样的,就是把数组分成两部分分别使其有序最后在组合起来就整体有序了。不同的是快速排序并不是平均拆分数组,而是选择一个中心点,排序时让中心点左边的数都比中心点小,中心点右边数都比中心点大,这个排序算法的时间复杂度是O(n), 但是由于数组拆分是基于中心点的,所以它的拆分的时间复杂度和它选择的这个点有很大关系,具体情况可以看代码分析。

二、算法

归并排序

/** * * 归并排序 * 用到的分治的思想 * 假如一个数组 前半部分和后半部分都是有序的, 那么它的排序时间复杂度是O(n) * 那么有: * A(m, n) = A(m, k) + A(k + 1, n) * 当 m = k 时 说明数组只有一个数字那么它自然有序了 * 同理n = k + 1 也是 * 所以我们只需要把数组 拆成 长度为一个 数组集,排序后再组合起来那么整个数组就有序了 * 那么剩下我们就要看看把数组 拆成 长度为一的数组集,需要的时间复杂度是多少 * * 假如数组长度 为 n, 我们每次 拆一半,最终得到 数组长度为1 * 数学等式可以写为: * n*(1/2)^x = 1 => 2^x = n => x = log(2)n (注意n是log的真数) => O(logn) * * 所以整个算法的时间复杂度为: O(nlogn) * * * @param s * */ public function MergeSort(s:Array):void { Merge(s,0, s.length - 1); } private function Merge(s:Array, m:int, n:int):Array { var temp:Array = []; //假如相等,说明不能再分了就终止了 if(m == n) { temp[0] = s[m]; return temp; } var k:int = Math.floor((m + n) / 2); var t1:Array = Merge(s, m, k); var t2:Array = Merge(s, k + 1, n); //这里合并成一个 var q:int = 0, p:int = 0; for(var i:int = 0; p <= k - m && q <= n - k - 1; i++) { if(t1[p] < t2[q]) { temp[i] = t1[p]; p++; }else { temp[i] = t2[q]; q++; } } //把剩下的补齐 while(p <= k-m) { temp[temp.length] = t1[p]; p++; } while(q <= n - k - 1) { temp[temp.length] = t2[q]; q++; } return temp; }

快速排序

/** *快速排序 * 用到的分治的思想 * 假如一个数组 前半部分和后半部分都是有序的, 那么它的排序时间复杂度是O(n) * 那么有: * A(m, n) = A(m, k) + A(k + 1, n) * 当 m = k 时 说明数组只有一个数字那么它自然有序了 * 同理n = k + 1 也是 * 所以我们只需要把数组 拆成 长度为一个 数组集,排序后再组合起来那么整个数组就有序了 * 那么剩下我们就要看看把数组 拆成 长度为一的数组集,需要的时间复杂度是多少 * * 注意拆分的策略和归并排序不一样, 这里的拆分和选择的对比点有很大关系 * 我们每次选择最后一个点 * 假如选择点能平分数组 那么时间复杂度就和归并排序一样 O(logn) * * 假如数组是有序的 [1,2,3,4,5,6,7,8], * 那么我们拆分的情况就是 * [1,2,3,4,5,6,7,8] => [1,2,3,4,5,6,7] | 8 => [1,2,3,4,5,6] | 7,8 => ... => [] | 1,2,3,4,5,6,7,8 * 可以看出总共要进行n次拆分 所以时间复杂度是O(n) * * 而如果输入是完全无序的[8,7,6,5,4,3,2,1] * 那么我们的拆分情况是 * [1,2,3,4,5,6,7,8] => 1 | [2,3,4,5,6,7,8] => 1,2 | [3,4,5,6,7,8] => ... => 1,2,3,4,5,6,7,8 | [] * 也是O(n) * * 所以可以看出,中心点的选择是很重要的,我们需要尽量选择可以平分数组的点 * 它最好的情况是 O(nlogn), 最差的情况是 O(n²) * * @param s * */ public function QuickSort(s:Array):void { Quick(s, 0, s.length - 1); } private function Quick(s:Array, m:int, n:int):void { // if(m >= n) { return; } //每次都选最后一个作为中心点 var j:int = m;//已排序区域起始序号 var value:int; //排序 for(var i:int = m; i < n; i++) { if(s[i] < s[n])//假如元素比中心点的这个小, 则把它交换到已排序区域的最后一位 { value = s[j]; s[j] = s[i]; s[i] = value; j++; }else//否则假如元素比它大,则不做任何交换 { } } //排序完成之后把最后一个值,与已排序列表的最后一位交换 value = s[j]; s[j] = s[n]; s[n] = value; trace(s); Quick(s, m, j - 1); Quick(s, j + 1, n); }
转载请注明原文地址: https://www.6miu.com/read-5038503.html

最新回复(0)