排序算法维度对比

  • 稳定。 如果a原本在b前面,而a=b,排序之后a仍然在b的前面;反之则不稳定
  • 时间复杂度。 运行完一个程序所需时间的长久
  • 空间复杂度。 运行完一个程序所需内存的大小

排序对比:
排序对比

排序分类:
排序分类

冒泡排序

介绍

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

算法描述

<1>.比较相邻的元素。如果第一个比第二个大,就交换它们两个;

<2>.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;

<3>.针对所有的元素重复以上的步骤,除了最后一个;

<4>.重复步骤1~3,直到排序完成。

动态展示

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

改进后方案

改进冒泡排序原理: 设置一标志性变量pos,用于记录每趟排序中最后一次进行交换的位置。由于pos位置之后的记录均已交换到位,故在进行下一趟排序时只要扫描到pos位置即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function bubbleSort2(arr) {
console.time('改进后冒泡排序耗时');
var i = arr.length-1; //初始时,最后位置保持不变
while ( i> 0) {
var pos= 0; //每趟开始时,无记录交换
for (var j= 0; j< i; j++)
if (arr[j]> arr[j+1]) {
pos= j; //记录交换的位置
var tmp = arr[j]; arr[j]=arr[j+1];arr[j+1]=tmp;
}
i= pos; //为下一趟排序作准备
}
console.timeEnd('改进后冒泡排序耗时');
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(bubbleSort2(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

选择排序

介绍

选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

算法描述

<1>. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

<2>. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

<3>. 重复第二步,直到所有元素均排序完毕。

动态展示

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
console.time('选择排序耗时');
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;
}
console.timeEnd('选择排序耗时');
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(selectionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

插入排序

介绍

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

算法实现

<1>.从第一个元素开始,该元素可以认为已经被排序;

<2>.取出下一个元素,在已经排序的元素序列中从后向前扫描;

<3>.如果该元素(已排序)大于新元素,将该元素移到下一位置;

<4>.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

<5>.将新元素插入到该位置后;

<6>.重复步骤2~5。

动态展示

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function insertionSort(array) {
if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
console.time('插入排序耗时:');
for (var i = 1; i < array.length; i++) {
var key = array[i];
var j = i - 1;
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}
console.timeEnd('插入排序耗时:');
return array;
} else {
return 'array is not an Array!';
}
}

改进二分查找方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function binaryInsertionSort(array) {
if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
console.time('二分插入排序耗时:');

for (var i = 1; i < array.length; i++) {
var key = array[i], left = 0, right = i - 1;
while (left <= right) {
var middle = parseInt((left + right) / 2);
if (key < array[middle]) {
right = middle - 1;
} else {
left = middle + 1;
}
}
for (var j = i - 1; j >= left; j--) {
array[j + 1] = array[j];
}
array[left] = key;
}
console.timeEnd('二分插入排序耗时:');

return array;
} else {
return 'array is not an Array!';
}
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(binaryInsertionSort(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

快速排序

介绍

快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

算法实现

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

<1>.从数列中挑出一个元素,称为 “基准”(pivot);

<2>.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

<3>.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

动态展示

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*方法说明:快速排序
@param array 待排序数组*/
//方法一
function quickSort(array, left, right) {
console.time('1.快速排序耗时');
if (Object.prototype.toString.call(array).slice(8, -1) === 'Array' && typeof left === 'number' && typeof right === 'number') {
if (left < right) {
var x = array[right], i = left - 1, temp;
for (var j = left; j <= right; j++) {
if (array[j] <= x) {
i++;
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
quickSort(array, left, i - 1);
quickSort(array, i + 1, right);
}
console.timeEnd('1.快速排序耗时');
return array;
} else {
return 'array is not an Array or left or right is not a number!';
}
}

//方法二
var quickSort2 = function(arr) {
console.time('2.快速排序耗时');
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
console.timeEnd('2.快速排序耗时');
  return quickSort2(left).concat([pivot], quickSort2(right));
};

var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(quickSort(arr,0,arr.length-1));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
console.log(quickSort2(arr));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

算法实例

查找两个字符串的最长公共子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function findSubStr(arr1, arr2) {
var sstr = '';
var L1 = arr1.length;
var L2 = arr2.length;
if (L1 > L2) {
var temp = arr1;
arr1 = arr2;
arr2 = temp;
L1 = arr2.length;
}
for (var j = L1; j > 0; j--)
for (var i = 0; i <= L1 - j; i++) {
sstr = arr1.substr(i, j);
if (arr2.indexOf(sstr) >= 0){
return sstr;
}
}
return '';
}


function findMaxSubstr(str1, str2){
var shorter = str1;
var longer = str2;
//判断长短
if(str1.length > str2.length){
shorter = str2;
longer = str1;
}else{
shorter = str1;
longer = str2;
}

//判断
for(var subLength=shorter.length; subLength>0; subLength--){
for(var i=0; i<=shorter.length-subLength; i++){
var subString = shorter.substring(i,i+subLength);
if(longer.indexOf(subString) >= 0){
var targetString = subString;
return targetString;
}
}
}
}

统计一个字符串出现频率最高的字母/数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const getMaxChar = str => {
let string = [...str];
let maxValue = '';
let obj = {};
let max = 0;

string.forEach(value => {
obj[value] = obj[value] == undefined ? 1 : obj[value] + 1
if (obj[value] > max) {
max = obj[value]
maxValue = value
}
})
return maxValue;
}

颠倒字符串

1
2
3
function reverseBySeparator(str) {
return str.split('').reverse().join('');
}

判断大括号是否闭合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function isBalanced(expression) {
var checkString = expression;
var stack = [];

// If empty, parentheses are technically balanced
if (checkString.length <= 0) return true;

for (var i = 0; i < checkString.length; i++) {
if(checkString[i] === '{') {
stack.push(checkString[i]);
} else if (checkString[i] === '}') {
// Pop on an empty array is undefined
if (stack.length > 0) {
stack.pop();
} else {
return false;
}
}
}

// If the array is not empty, it is not balanced
if (stack.pop()) return false;
return true;
}
isBalanced('{}{')



来源于1:https://juejin.im/post/57dcd394a22b9d00610c5ec8
来源于2:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html