排序算法:
冒泡排序:频繁交换 ,找出其中最大的放到最后一个 一次找到第二大的放大倒数第二个...最后完成
function bubbleSort(arr) {
for (let i = 0;i < arr.length - 1;i++) {
for (let j = 0;j < arr.length - 1 - i;j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
return arr;
}
选择排序:
从开头选择一个基准值 遍历一趟选出比这个更小的值最后当前位置与找出来的最终值交换。排列顺序是从前到后
function xuanzeSort(arr) {
for (let i = 0, min, index;i < arr.length;i++) {
min = arr[i];
index = i;
for (let j = i + 1;j < arr.length;j++) {
if (min > arr[j]) {
min = arr[j];
index = j;
}
}
arr[index] = arr[i]
arr[i] = min;
}
return arr;
}
插入排序:
跟我们的打牌一样: 从第一个开始 拿到这个值往前比较 找到比它小的值的时候停下来放在这里,简单就是 找到合适的位置然后插入进去
function charuSort(arr) {
let index, current;
for (let i = 1;i < arr.length;i++) {
index = i - 1;
current = arr[i]
while (current < arr[index] && index >= 0) {
arr[index + 1] = arr[index];
index--;
}
arr[index + 1] = current;
}
return arr;
}
快速排序
把数据分成两组,选择最中间的一个值 前后分成两个,比中间这个值大的放后面 比这个值小的放在前面。然后递归排列前后数组即可
var quickSort = function (arr) {
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]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
};
希尔排序:是对插入排序的优化。插入排序一次移动一位,而希尔排序是一次移动gap位。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
为更加清晰地说明该排序,贴一张其它地方转载而来的图片
这个代码我看了好一段时间,都有点懵 难理解,最后弄个例子程序一步一步走才看懂了。哎 我真笨
其实这个图对我来说有点误导性。
图上看起来是一组一组的排好序的,但是并不是。 而是设置一个值j = gap的时候,就依次排,排到最后一个 ,只是移动的间隔为gap。上图上的分组是同时在进行排序。这样排到后面的时候前面相应间隔的数是已经排好序了的。
//希尔排序
function shellSort(arr) {
let len = arr.length;
// gap 即为增量
for (let gap = Math.floor(len / 2);gap > 0;gap = Math.floor(gap / 2)) {
debugger
for (let i = gap;i < len;i++) {
let j = i;
let current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
return arr;
}
let arr = [8, 5, 6, 1, 7, 3, 2, 4];
console.log(shellSort(arr));
希尔排序比直接插入排序优点:
直接插入排序的问题:如果在后面来了一个特别小的元素,需要全部移动,那么排序的效率特别低。
希尔排序优点:如果在数组最后加入一个小元素,他会被很快移到最前面。
归并排序
基本思想:先递归的分解数列,再合并数列
(1)将一个数组拆成A、B两个小组,两个小组继续拆,直到每个小组只有一个元素为止。
(2)按照拆分过程逐步合并小组,由于各小组初始只有一个元素,可以看做小组内部是有序的,合并小组可以被看做是合并两个有序数组的过程。
(3)对左右两个小数列重复第二步,直至各区间只有1个数。
代码实现:
//辅助函数,传入两个数组,按大小顺序插入新数组然后返回。
function Merger(a, b) {
var n = a && a.length;
var m = b && b.length;
var c = [];
var i = 0, j = 0;
while (i < n && j < m) {
if (a[i] < b[j])
c.push(a[i++]);
else
c.push(b[j++]);
}
while (i < n)
c.push(a[i++]);
while (j < m)
c.push(b[j++]);
console.log("将数组", a, '和', b, '合并为', c)
return c;
}
//划分数组
function merge_sort(arr) {
console.log(arr)
if (arr.length == 1)
return arr
var mid = Math.floor(arr.length / 2)
var left = arr.slice(0, mid)
var right = arr.slice(mid)
return Merger(merge_sort(left), merge_sort(right)); //合并左右部分
}
let arr = [8, 5, 6, 1, 7, 3, 2, 4];
console.log(merge_sort(arr));
原文:归并排序
堆排序
大佬链接:堆排序
前面步骤看懂了,后面看代码有点绕
//堆排序
// 交换两个节点
function swap(A, i, j) {
let temp = A[i];
A[i] = A[j];
A[j] = temp;
}
// 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
// 假设 结点 i 以下的子堆已经是一个大顶堆,shiftDown函数实现的
// 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。后面
// 将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
// 都执行 shiftDown操作,所以就满足了结点 i 以下的子堆已经是一大
//顶堆
function shiftDown(A, i, length) {
let temp = A[i]; // 当前父节点
// j= 0;i--) {
shiftDown(A, i, A.length);
}
// 排序,每一次for循环找出一个当前最大值,数组长度减一
for (let i = Math.floor(A.length - 1);i > 0;i--) {
swap(A, 0, i); // 根节点与最后一个节点交换
shiftDown(A, 0, i); // 从根节点开始调整,并且最后一个结点已经为当
// 前最大值,不需要再参与比较,所以第三个参数
// 为 i,即比较到最后一个结点前一个即可
}
return A;
}
let arr = [8, 5, 6, 1, 7, 3, 2, 4];
console.log(heapSort(arr));
下面循环调用的shiftDown的时候 是从上到下,并把下面的非叶子节点的大小顺序移动(??)
暂时不懂 有空再弄
堆排序是不同的选择排序。