排序图解:js排序算法实现

之前写过js实现数组去重, 今天继续研究数组: 排序算法实现。 排序是数据结构主要内容,并不限于语言主要在于思想;大学曾经用C语言研究过一段时间的排序实现, 这段时间有空用JS再将排序知识点熟悉一遍。
理解排序不得不提的是日本人实现的一个排序动画站, 该站对于研究排序大有益处。当然本文的排序算法并不与其一致, 本文是9种js排序实现的实践与完善: 理解其9种算法然后使每种算法代码均能正常运行。
1.插入排序
最普通的排序算法, 从数组下标1开始每增1项排序一次,越往后遍历次数越多;
原理图:

代码:
// 插入排序 从下标1开始每增1项排序一次,越往后遍历次数越多
function sort1(array) {
var len = array.length,
i, j, tmp, result; // 设置数组副本
result = array.slice();
for(i=; i < len; i++){
tmp = result[i];
j = i - ;
while(j>= && tmp < result[j]){
result[j+] = result[j];
j--;
}
result[j+] = tmp;
}
return result;
}
2.二分插入排序
插入排序的一种优化实现, 通过二分法减少遍历时间。
原理图:

代码:
// 先在有序区通过二分查找的方法找到移动元素的起始位置,
// 然后通过这个起始位置将后面所有的元素后移
function sort2(array) {
var len = array.length,
i, j, tmp, low, high, mid, result;
// 赋予数组副本
result = array.slice(0);
for(i = 1; i < len; i++){
tmp = result[i];
low = 0;
high = i - 1;
while(low <= high){
mid = parseInt((low + high)/2, 10);
if(tmp < result[mid]) high = mid - 1;
else low = mid + 1;
}
for(j = i - 1; j >= high+1; j--){
result[j+1] = result[j];
}
result[j+1] = tmp;
}
return result;
}
3.希尔排序
其排序思路有点复杂, 需花多点时间理解;排序思路:先将整个待排序记录序列分割成若干个子序列,在序列内分别进行直接插入排序,待整个序列基本有序时,再对全体记录进行一次直接插入排序。
原理图:

代码:
// 希尔排序:先将整个待排序记录序列分割成若干个子序列
// 在序列内分别进行直接插入排序,待整个序列基本有序时,
// 再对全体记录进行一次直接插入排序
function sort3(array){
var len = array.length, gap = parseInt(len/2),
i, j, tmp, result;
// 复制数组
result = array.slice(0);
while(gap > 0){
for(i = gap; i < len; i++){
tmp = result[i];
j = i - gap;
while(j>=0 && tmp < result[j]){
result[j + gap] = result[j];
j = j - gap;
}
result[j + gap] = tmp;
}
gap = parseInt(gap/2);
}
return result;
}
4.冒泡排序
很常见很容易理解的排序算法, 排序思路:遍历数组,每次遍历就将最大(或最小)值推至最前。越往后遍历查询次数越少, 跟插入排序刚好相反。
原理图:

代码:
// 冒泡排序 每次将最小元素推至最前
function sort4(array) {
var len = array.length,
i, j, tmp, result;
result = array.slice(0);
for (i = 0; i < len; i++) {
for (j = len - 1; j > i; j--) {
if (result[j] < result[j - 1]) {
tmp = result[j - 1];
result[j - 1] = result[j];
result[j] = tmp;
}
}
}
return result;
}
5.改进冒泡排序
对上述冒泡排序的一种优化, 优化思路:当一次遍历前后数组不产生变化时,说明该数组已经有序,结束排序。
原理图:

代码:
// 如果在某次的排序中没有出现交换的情况,
// 那么说明在无序的元素现在已经是有序了,就可以直接返回了。
function sort5(array) {
var len = array.length,
i, j, tmp, exchange, result; result = array.slice(0);
for (i = 0; i < len; i++) {
exchange = 0;
for (j = len - 1; j > i; j--) {
if (result[j] < result[j - 1]) {
tmp = result[j];
result[j] = result[j - 1];
result[j - 1] = tmp;
exchange = 1;
}
}
if (!exchange) return result;
}
return result;
}
6.快速排序
快速排序在诸多算法排序中可能不是最好的, 但个人认为在JS语言实现中是最快的!以前公司项目中对比过二分插入排序、优化冒泡排序、快速排序的JS实现执行时间,几千条数据的数组在firefox下快速排序的速度比冒泡、插入排序快3至4秒(数组元素为复杂的对象,根据对象某一属性值排序)。阮一峰老师研究JS实现排序时曾只针对该种排序进行讲解:javascript的快速排序实现。
原理图:

代码:
//(1)在数据集之中,选择一个元素作为"基准"(pivot)。
//(2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。
//(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
function sort6(array) {
var tmp_array = array.slice(0), result,
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));
};
result = quickSort(tmp_array);
return result;
}
7.选择排序
实现思路跟冒泡排序差不多, 可以说是冒泡排序的衍生版本;
原理图:

代码:
// 在无序区中选出最小的元素,然后将它和无序区的第一个元素交换位置。
// 原理跟冒泡排序一样,算是冒泡的衍生版本
function sort7(array) {
var len = array.length,
i, j, k, tmp, result; result = array.slice(0);
for (i = 0; i < len; i++) {
k = i;
for (j = i + 1; j < len; j++) {
if (result[j] < result[k]) k = j;
}
if (k != i) {
tmp = result[k];
result[k] = result[i];
result[i] = tmp;
}
}
return result;
}
8.堆排序
因为js模拟二叉树比较麻烦,所以堆排序的优势用js语言无法体现, 相对而言C语言的链表在实现上更能表现堆排序,堆排序或许更适合指针类的计算机语言。本文注重图解各排序的基本思路,所以该排序的具体实现没讲太细, 如想深究实现细节请看:堆排序及其分析。
原理图:
1.调整二叉树,形成大根堆(子节点都比父节点小)。

2.交换堆第一元素跟最后元素位置,最后元素弹出堆。然后继续回到1,调整堆。

3.重复2, 当所有节点弹出堆后;弹出的节点值就是有序的了。

代码:
// 1) 初始堆:将原始数组调整成大根堆的方法——筛选算法:子节点都比父节点小
// 2) 堆排序: 每次将堆顶元素与数组最后面的且没有被置换的元素互换。
// 参考代码: http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/
function sort8(array) {
var result = array.slice(0); function swap(array, i, j) {
var temp = array[i];
array[i] = array[j];
array[j] = temp;
} function maxHeapify(array, index, heapSize) {
var iMax, iLeft, iRight;
while (true) {
iMax = index;
iLeft = 2 * index + 1;
iRight = 2 * (index + 1); if (iLeft < heapSize && array[index] < array[iLeft]) {
iMax = iLeft;
} if (iRight < heapSize && array[iMax] < array[iRight]) {
iMax = iRight;
} if (iMax != index) {
swap(array, iMax, index);
index = iMax;
} else {
break;
}
}
} function buildMaxHeap(array) {
var i, iParent = Math.floor(array.length / 2) - 1; for (i = iParent; i >= 0; i--) {
maxHeapify(array, i, array.length);
}
} function sort(array) {
buildMaxHeap(array); for (var i = array.length - 1; i > 0; i--) {
swap(array, 0, i);
maxHeapify(array, 0, i);
}
return array;
} return sort(result);
}
9.归并排序
很容易理解且执行效率一般(js实现)的排序, 排序思路:将无序的数组 拆成N部分进行有序处理,然后合并;
原理图:

代码:
// 合并排序:将无序的数组 拆成N部分进行有序处理,然后合并;
// 参考代码: https://gist.github.com/paullewis/1982121
function sort9(array) {
var result = array.slice(0); // 递归调用合并函数
function sort(array) {
var length = array.length,
mid = Math.floor(length * 0.5),
left = array.slice(0, mid),
right = array.slice(mid, length); if (length === 1) {
return array;
}
return merge(sort(left), sort(right));
} // 合并 两有序的数组
function merge(left, right) {
var result = []; while (left.length || right.length) { if (left.length && right.length) { if (left[0] < right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
} } else if (left.length) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
return result;
} return sort(result);
}
本文代码及demo:
参考文章:
1.排序动画站;
2.9种js排序实现;
4.堆排序及其分析;
5.常见排序算法;
排序图解:js排序算法实现的更多相关文章
- 图解冒泡排序及算法优化(Java实现)
冒牌排序 基本思想 定义:冒泡排序的英文是bubblesort,它是一种基础的交换排序 原理:每次比较两个相邻的元素,将较大的元素交换至右端 (升序排序) 思路:相邻的元素两两比较,当一个元素大于右侧 ...
- js排序算法汇总
JS家的排序算法 十大经典算法排序总结对比 一张图概括: 主流排序算法概览 名词解释: n: 数据规模k:“桶”的个数In-place: 占用常数内存,不占用额外内存Out-place: 占用额外 ...
- 总结下js排序算法和乱序算法
其实本人最怕的就是算法,大学算法课就感觉老师在讲天书,而且对于前端来说,算法在实际的应用中实在是很有限.毕竟算法要依靠大量的数据为基础才能发挥出算法的效率,就浏览器那性能,......是吧,退一万步说 ...
- js排序算法总结—冒泡,快速,选择,插入,希尔,归并
相信排序是任何一个程序猿都会用到的东西,今天简单总结记录下常见的排序算法. 一.冒泡排序 说起冒泡排序,可能每个人都不会陌生,实现思路相当简单明了,就是不停的对数组进行两两比较,将较大(较小)的一项放 ...
- js排序算法总结——冒泡,快速,选择,插入,希尔,归并
相信排序是任何一个程序猿都会用到的东西,今天简单总结记录下常见的排序算法. 一.冒泡排序 说起冒泡排序,可能每个人都不会陌生,实现思路相当简单明了,就是不停的对数组进行两两比较,将较大(较小)的一项放 ...
- 图解选择排序及算法优化(Java实现)
选择排序 前言 原理:每次循环对比找出最小/大值,将最值的元素交换至左侧 思想:直接选择排序(Straight Select Sort)算法思想:第一趟从n个元素的数据序列中选出关键字最小/大的元素并 ...
- js排序算法06——希尔排序
希尔排序本质是一种插入排序,由一位叫希尔的大神提出得名,其基本思想是将数组分组进行插入排序,每次消除不止一个逆序对,这样就提高了插入排序的效率.最后一步进行一间隔的插入排序,此时数组已经基本有序.代码 ...
- JavaScript实现获取两个排序数组的中位数算法示例
本文实例讲述了JavaScript排序代码实现获取两个排序数组的中位数算法.分享给大家供大家参考,具体如下: 题目 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个 ...
- JavaScript 数据结构与算法之美 - 桶排序、计数排序、基数排序
1. 前言 算法为王. 想学好前端,先练好内功,只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算 ...
随机推荐
- Java Gradle入门指南之简介、安装与任务管理
这是一篇Java Gradle入门级的随笔,主要介绍Gradle的安装与基本语法,这些内容是理解和创建build.gradle的基础,关于Gradle各种插件的使用将会在其他随笔中介绍. ...
- Redis简介
Redis是一个偏重于in-memory的key-value数据库,这样讲有点儿不准确,但是很容易将Redis简单分类.更准确的讲Redis是一个数据结构的存储服务.它的value不仅仅只有strin ...
- Javascript之旅——第六站:看看writable特性
说起js中的那些特性标记,总觉得有些怪怪的,那为什么要说到这个attribute,起源于对一个问题的疑问,我们都知道window对象其实就是 浏览器窗口的一个实例,既然是一个实例,那这个实例就应该有“ ...
- 【JSP】JSP基础学习记录(四)—— Servlet
序: 众所周知JSP的基础也就是Servlet,如果单纯用Servlet类来响应用户的HTTP请求可以吗?答案是肯定的.JSP中的9个内置对象只是自动帮我们初始化的,没有他们一样可以实现web.只是工 ...
- openstack-kilo--issue(十一)Failed connect to 169.254.169.254:80; No route to host
# curl http://169.254.169.254/latest/user-data curl: () Failed connect to ; No route to host 解决方案: c ...
- Java api 入门教程 之 JAVA的IO处理
IO是输入和输出的简称,在实际的使用时,输入和输出是有方向的.就像现实中两个人之间借钱一样,例如A借钱给B,相对于A来说是借出,而相对于B来说则是借入.所以在程序中提到输入和输出时,也需要区分清楚是相 ...
- 烂泥:puppet3.7安装与配置
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 有关服务器的自动化管理,这方面以前没有接触过.打算这段时间把这块知识给补上. 现在服务器自动化管理软件,使用最多也最火的就是puppet了. 那么我们今 ...
- linux权限补充:rwt rwT rws rwS 特殊权限
众所周知,Linux的文件权限如: 777:666等,其实只要在相应的文件上加上UID的权限,就可以用到加权限人的身份去运行这个文件.所以我们只需要将bash复制出来到另一个地方,然后用root加上U ...
- JQuery中的extend函数
1.jQuery.fn.extend(object) 扩展 jQuery 元素集来提供新的方法(通常用来制作插件). 例如:增加两个插件方法. jQuery.fn.extend({ check: fu ...
- C++ 中 typename
声明template参数时, 前缀关键字class和typename可以互换; 使用关键字typename标识嵌套从属类型名称, 但不需在基类列表和成员初始化列表内使用. 从属名称(dependent ...