排序算法是面试时面试官经常提的问题,最初的时候我只是死记硬背,现在花时间理解透每一个算法背后的真谛,做到理解熟记于心
交换排序:冒泡排序与快速排序
插入排序:直接插入排序与折半插入排序以及希尔排序
选择排序:简单选择排序与堆排序
归并排序
基数排序
1.冒泡排序
冒泡排序的算法思想是就是不停地比较相邻记录的关键字,如果不满足排序要求,就交换相邻记录,直到所有的记录已经排好序为止。
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { //相邻元素两两对比
var temp = arr[j+1]; //元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
2.快速排序
快速排序思想:
(1)待排序序列S中任意选择一个记录r作为轴值(记录r的关键字为k)。
(2)将剩余的记录分割成两个子序列L和R,子序列L中的关键字均小于或等于k,子序列R中所含记录的关键字均大于或等于k。
(3)将子序列L中所有记录放在记录r左边,子序列R中所有记录放在记录r右边,此时记录r左边记录的关键字小于或等于k,记录r右边的关键字大于或等于k,因此记录r整好处于正确的位置。
(4)对于子序列L和R递归进行快速排序,直到子序列中只含有0或1个元素,退出递归。
在具体实现时步骤(2)、(3)可以同时实现,即在分割的过程中将所有小于等于轴值得记录放在轴值r左边,将大于或等于它的记录放在它的右边。这个过程的实现是通过交换记录来实现的。快速排序算法的关键在于分割过程的实现。
function quickSort(arr) {
// 交换
function swap(arr, a, b) {
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
// 分区
function partition(arr, left, right) {
/**
* 开始时不知最终pivot的存放位置,可以先将pivot交换到后面去
* 这里直接定义最右边的元素为基准
*/
var pivot = arr[right];
/**
* 存放小于pivot的元素时,是紧挨着上一元素的,否则空隙里存放的可能是大于pivot的元素,
* 故声明一个storeIndex变量,并初始化为left来依次紧挨着存放小于pivot的元素。
*/
var storeIndex = left;
for (var i = left; i < right; i++) {
if (arr[i] < pivot) {
/**
* 遍历数组,找到小于的pivot的元素,(大于pivot的元素会跳过)
* 将循环i次时得到的元素,通过swap交换放到storeIndex处,
* 并对storeIndex递增1,表示下一个可能要交换的位置*
*/
swap(arr, storeIndex, i);
storeIndex++;
}
}
// 最后: 将pivot交换到storeIndex处,基准元素放置到最终正确位置上
swap(arr, right, storeIndex);
return storeIndex;
}
function sort(arr, left, right) {
if (left > right) return;
var storeIndex = partition(arr, left, right);
sort(arr, left, storeIndex - 1);
sort(arr, storeIndex + 1, right);
}
sort(arr, 0, arr.length - 1);
return arr;
}
3.选择排序
思想:选择排序的基本思想是:每一趟在n-i+1(i=1,2,...n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { //寻找最小的数
minIndex = j; //将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
4.堆排序
堆排序:对n个元素进行堆排序,先将其建成堆,以根结点与第n个结点交换;调整前n-1个结点成为堆,再以根结点与第n-1个结点交换;重复上述操作,直到整个序列有序。
堆排序须知:
堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
var len; //因为声明的多个函数都需要数据长度,所以把len设置成为全局变量
function buildMaxHeap(arr) { //建立大顶堆
len = arr.length;
for (var i = Math.floor(len/2); i >= 0; i--) {
heapify(arr, i);
}
}
function heapify(arr, i) { //堆调整
var left = 2 * i + 1,
right = 2 * i + 2,
largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
heapify(arr, largest);
}
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function heapSort(arr) {
buildMaxHeap(arr);
for (var i = arr.length-1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0);
}
return arr;
}
5.直接插入排序
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex+1] = arr[preIndex];
preIndex--;
}
arr[preIndex+1] = current;
}
return arr;
}
6.希尔排序
其思想是:先将待排序序列分割为若干个子序列分别进行直接插入排序;待整个序列基本有序时,在对全体记录进行一次直接插入排序。
function shellSort(arr) {
var len = arr.length,
temp,
gap = 1;
while(gap < len/3) { //动态定义间隔序列
gap =gap*3+1;
console.log('gap',gap)
}
for (gap; gap> 0; gap = Math.floor(gap/3)) {
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i-gap; j >= 0 && arr[j]> temp; j-=gap) {
arr[j+gap] = arr[j];
}
arr[j+gap] = temp;
}
}
return arr;
}