今天来总结一下算法中比较常见的几种排序方法
首先我们定义一个简单无序数组[4,1,6,9,3,2,8,7]
首先排序不是单纯的比较大小,其本质是负责比较和交换
首先提出三个方法模型
function compare(a,b) { //比较之后需要得出是否需要交换
if (b > a ) return true;
else return false;
}
function exchange (arr,a,b) { //将数组内a和b负责交换
var temp = arr[a];
arr[a] = arr[b]
arr[b] = temp;
}
function sort(arr) { //排序方法
}
- 冒泡排序
冒泡排序简单来讲就是比较相邻两个位置,如果符合条件就互换位置,如果不符合则继续向下比较,如开始比较1和4,如果按照降序排列4比1大,则位置无需调换,继续比较1和6,1比6小则两个位置互换 继续向下比较,当走完一轮之后则将最小的数字1调换到了这个数组的末尾项,将这个方法循环该数组长度次数-1次就可以得到一个降序的数组
function sort(arr) { //排序方法
for (var i = 0 ; i < arr.length ; i++ ) {
for (var j = 0 ; j < arr.length -1 ; j++) {
if(compare(arr[j], arr[j + 1])){
exchange(arr, j, j+1);
}
}
}
但是当我们写完之后发现,当经过第一轮之后,整个数组的最小值已经确定,所以倒数第二小的数字当排到倒数第二的位置时候就不用再和它的下一位置进行比较,所以我们可以再优化一下代码
function sort(arr) { //排序方法
for (var i = 0 ; i < arr.length ; i++ ) {
for (var j = 0 ; j < arr.length -1 -i ; j++) {
if(compare(arr[j], arr[j + 1])){
exchange(arr, j, j+1);
}
}
}
}
- 选择排序
选择排序顾名思义,每一次循环中将最符合条件的数获取到,进行位置交换,如第一次循环得到最大的数9 将其放到这个数组的末尾,这样我们可以抽象的看成这个数组中前七位是无序的[4 , 1,6 , 7,3 , 2,8]以及最后一位有序的{9},这样在确保最后一位是有序的前提下,将剩余无序数组再进行筛选,依次循环 直到数组中全都是秩序数字,
function sort(arr) { //排序方法
for (var i = 0 ; i < arr.length ; i++ ) {
var maxIndex = 0;
for (var j = 0 ; j < arr.length -i ; j++) {
if(compare(arr[maxIndex], arr[j])){
maxIndex = j;
}
}
exchange(arr,maxIndex,arr.length - 1 -i );
}
}
- 简单快速排序
快速排序图文说明可以参考这个https://blog.csdn.net/nrsc272420199/article/details/82587933
我帮大家简单解释和梳理一下脉络
快速排序的基本思想在于 在数组中选出一个数字为基准,前后分为两个指针,两个指针分别代表 大 与 小 大指针负责过滤掉比选中值大的项,小指针负责过滤掉小的项 若遇到不符合条件则将当前指针的值赋值给另外一个指针,并且暂停该指针启动另一个指针,依次循环知道两个指针接触停止 当前位置负责盛放我们选中的数值
简单来讲,抽象一下这个概念,我们可以简单抽象一下 我们选出一个数值作为基准 从左到右 比基准小的放左边 比基准大的放右边,此时我们就可以抽象理解为我们获得三个秩序的 数组分别是 [比基准小的] , [基准] ,[比基准大的] 这三个数组来看小 中 大 以数组和数组之间的关系来看这三个是非常符合秩序的 但是他们内部数组排序是混乱的,除非他们的数组内部只有一个数字 比如说[1][2][3],但是我们遇到问题时候数组长度是不定的,所以除了我们选出来的[基准]数组以外,剩下两个数组都是具有一个或一个以上的数,从左来看,我们先分析[比基准值小] 的数组 此时问题又回到了最初的起始,我们又选出一个基准值 获得三个秩序数组 继续拆分继续拆分,直到每一个[比基准值小]和[比基准值大]的数组内容小于或等于1个数组的时候,我们可以迅速串联起来形成一个有序数组
解释一下
数字化[4,1,6,9,3,2,8,7]
首先我们选出4位基准 第一轮快速排序
[1,3,2] [4] [6,9,8,7]
得到三个秩序数组 但是左右两边的秩序数组内容是混乱的,我们对他进行第二轮清洗,
因为中间的基准值数组只有一项 所以无论是内容 还是数组 都是秩序的
[1,3,2] 这个数组我们选出1为基准 [6, 9,8, 7]我们选6为基准 则第二轮清洗结果如下显示
[] [1] [3,2] [4] [] [6] [9, 8,7,]
同理因为我们断定当数组内容小于或等于一个的时候其本身就是秩序的,所以继续对超过1项的秩序数组进行排序
[] [1] [2] [3] [] [4] [] [6] [8,7] [9] []
依次进行下去直到每一个秩序数内容小于等于一项时停止分化
[] [1] [2] [3] [] [4] [] [6] [7] [8 ] [] [9] []
然后我们进行合并就获得一个秩序的数组了
该展示仅仅负责梳理思路 不代表运算方法及过程
function quickSort(arr) {
if (arr == null || arr.length == 0) return [];
var leader = arr[0];
var left = [];
var right = [];
for(var i= 1 ; i < arr.length; i++){
if (arr[i] < leader) left.push(arr[i]);
else right.push(arr[i]);
}
left = quickSort(left)
right = quickSort(right)
left.push(leader);
return left.concat(right)
}
而在标准快排时,我们使用双指针进行筛选,当两个指针都遇到不符当前指针规定的数字时交换内容继续筛选,直到相交或者相邻,此时再对前后两个数组继续使用双指针筛选 总体来说思想大同小异,表现手法略有差别,
function swap(arr,a,b) {
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
function quickSort(arr,begin,end) {
if(begin>= end -1) return;
var left = begin;
var right = end;
do{
do left++;while(left <right && arr[left]< arr[begin]);
do right -- ;while (right > left &&arr[right] > arr[begin]);
if(left < right) swap(arr,left,right)
}while(left<right);
var swapPoint = left == right ? right-1:right;
swap(arr,begin,swapPoint )
quickSort(arr,begin,swapPoint);
quickSort(arr,swapPoint+1,end)
}
quickSort(arr,0,arr.length)