快速排序简介
- 快速排序擅长于处理大数据集,当数据集较大时,我们一般使用快速排序。
- 快速排序也十分脆弱,经常会出现实际时间复杂度只有O(n^2)的情况。
- 快速排序的平均时间复杂度是O(n*logn)(n是数据集种数据个数)。
- 快速排序实际上是一种分治的排序算法,利用递归实现。
快速排序稳定性分析
快速排序不是1个稳定的排序方法。
快速排序的过程
1.选择一个基准元素pivot
2.把数组中小于pivot的数据放到pivot左侧,大于pivot的数据放到pivot右侧。
3.递归的进行这个过程,直到数组为空。
首先我们给出问题,我们想要对以下数据进行排序
接着我们根据上面给出的快速排序过程写出递归过程
1.每次递归需要做的事情,把大于基准元素的数据放到右侧,小于基准元素的数据放到左侧。
2.递归终点,当数组为空。
function quickSort(arr)
{
if(arr.length === 0) //递归终点
{
return [];
}
let left = [];
let right = [];
let pivot = arr[0];
for(let i = 1;i < arr.length;i++)
{
if(arr[i] < pivot)
{
left.push(arr[i]);
}
else
{
right.push(arr[i]);
}
}
return quickSort(left).concat(pivot,quickSort(right));
}
时间复杂度分析(利用递归recurrence和master throem)
- master throem
如果分治算法的递推式是 T(n) = aT(n/b) + O(n^d)(a>0,b>1,d>=0)
那么我们可以得到
- 递归的recurrence
从上面的代码可以看出,快速排序的递推式是 T(n) = 2T(n/2) + O(n),因此它的时间复杂度是O(n*logn)。
冒泡排序简介
- 冒泡排序的主要思想是比较相邻的2个元素,把更大的元素交换到后面。
- 冒泡排序需要两层循环实现。
冒泡排序稳定性分析
冒泡排序是一个稳定的排序方法,因为当遇到相等的元素的时候,冒泡排序不会将它们交换。
冒泡排序实现
function bubbleSort(arr)
{
for(let i = 0;i < arr.length;i++)
{
for(let j = 0;j < arr.length - 1 - i;j++)
{
if(arr[j] > arr[j + 1])
{
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
选择排序简介
- 选择排序是每次从未排序部分找出最小值和未排序部分的第一个元素交换。
- 选择排序需要嵌套循环。
- 选择排序的第一层循环的i的范围是从0到arr.length - 1,表示遍历所有元素,第二层循环的j的范围是从i+1到arr.length - 1,表示遍历所有未排序部分。
- 选择排序比冒泡排序快。
选择排序适用范围
- 选择排序适合比较小的数据。
选择排序稳定性分析
选择排序不是一个稳定的排序算法,如,[5,4,5,2,1],第一轮选择2和5交换,这就使得2个5的相对位置发生改变了,所以选择排序不稳定。
选择排序实现
function selectionSort(arr)
{
for(let i = 0;i < arr.length - 1;i++)
{
let min = arr[i];
let index = i;
for(let j = i + 1;j < arr.length;j++)
{
if(arr[j] < min)
{
min = arr[j];
index = j;
}
}
let temp = arr[i];
arr[i] = min;
arr[index] = temp;
}
return arr;
}
插入排序
- 插入排序的关键在于取出未排序部分的第一个元素,在排序部分找到插入位置。
- Chrome的JavaScript引擎使用了插入排序作为当元素小于10个时的排序方法。
- 插入排序比选择排序和冒泡排序快。
插入排序稳定性分析
插入排序是稳定的排序算法。
插入排序实现
function insertSort(arr)
{
for(let i = 1;i < arr.length;i++)
{
let temp = arr[i];
let num = i - 1;
while(num >= 0 && arr[num] > temp)
{
arr[num + 1] = arr[num];
num--;
}
arr[num + 1] = temp;
}
return arr;
}
归并排序
- 归并排序的过程是首先用递归的方法把大数组分割成只包含1个元素的小数组。
- 再用递归的方法,将每个小数组合并并排序。
- 归并排序使用的是分治法。
- FireFox使用归并排序作为sort方法的实现。
归并排序的稳定性分析
归并排序是稳定的排序算法。
归并排序适用范围
- 归并排序适合数据量较大的情况,如几百万个数据。
归并排序的实现
function mergeSort(arr)
{
if(arr.length > 1)
{
let mid = Math.floor(arr.length/2);
let left = mergeSort(arr.slice(0,mid));
let right = mergeSort(arr.slice(mid));
arr = merge(left,right);
}
return arr;
}
function merge(left,right)
{
let res = [];
let index1 = 0;
let index2 = 0;
while(index1 < left.length && index2 < right.length)
{
if(left[index1] < right[index2])
{
res.push(left[index1++]);
}
else{
res.push(right[index2++]);
}
}
return res.concat(index1 < left.length ? left.slice(index1):right.slice(index2));
}
排序算法稳定性
排序算法稳定性是指2个相等的数据的原本的相对位置在排序后不改变。
如,A1和A2相等,A1原本排在A2前面,如果排序后A1还是排在A2前面,那么排序算法就是稳定的。
排序算法稳定性的作用
- 当排序算法要排序的数组是由引用类型组成的,如,数组由自定义类型学生组成,原本数组按照学号升序排列,现在想按照年龄升序排列,如果排序算法是稳定的,那么相同年龄的学生还是按照学号升序排列的。