JavaScript排序算法之归并排序
2016-03-27 15:48
645 查看
归并排序的引入
归并排序的命名来自它的实现原理: 把一系列排好序的子序列合并成一个大的完整有序序列。 从理论上讲, 这个算法很容易实现。 我们需要两个排好序的子数组, 然后通过比较数据大小, 先从最小的数据开始插入, 最后合并得到第三个数组。 然而, 在实际情况中, 归并排序还有一些问题, 当我们用这个算法对一个很大的数据集进行排序时, 我们需要相当大的空间来合并存储两个子数组。 就现在来讲, 内存不那么昂贵, 空间不是问题, 因此值得我们去实现一下归并排序,
比较它和其他排序算法的执行效率。
自底向上的排序方法
采用非递归或者迭代版本的归并排序是一个自底向上的过程。 这个算法首先将数据集分解为一组只有一个元素的数组。
然后通过创建一组左右子数组将它们慢慢合并起来, 每次合并都保存一部分排好序的数据, 直到最后剩下的这个数组所有的数据都已完美排序。 下图演示了自底向上的归并排序算法如何运行的。
代码测试:
1.所调用的函数:
function CArray(numElements) {
this.dataStore = [];
this.toString = toString;
this.numElements = numElements;
this.setData = setData; //随机生成一组数
this.mergeSort=mergeSort;
this.mergeArrays=mergeArrays;
for (var i = 0; i < numElements; ++i) {
this.dataStore[i] = i;
}
}
function setData() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() *
(this.numElements+1));
}
}
function toString() {
var retstr = "";
for (var i = 0; i < this.dataStore.length; ++i) {
retstr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
retstr += "\n";
}
}
return retstr;
}
function mergeSort() {
if (this.dataStore.length < 2) {
return;
}
var step = 1;
var left, right;
while (step < this.dataStore.length) {
left = 0;
right = step;
while (right + step <= this.dataStore.length) {
mergeArrays(this.dataStore, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if (right < this.dataStore.length) {
mergeArrays(this.dataStore, left, left+step, right, this.dataStore.length);
}
step *= 2;
}
}
function mergeArrays(arr,startLeft, stopLeft, startRight, stopRight) {
var rightArr = new Array(stopRight - startRight + 1);
var leftArr = new Array(stopLeft - startLeft + 1);
k = startRight;
for (var i = 0; i < (rightArr.length-1); ++i) {
rightArr[i] = arr[k];
++k;
} k
= startLeft;
for (var i = 0; i < (leftArr.length-1); ++i) {
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length-1] = Infinity; // 哨兵值
leftArr[leftArr.length-1] = Infinity; // 哨兵值
var m = 0;
var n = 0;
for (var k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr
) {
arr[k] = leftArr[m];
m++;
}
else {
arr[k] = rightArr
;
n++;
}
}
alert("left array - ", leftArr[m]);
alert("right array - ", rightArr
);
}
说明:函数中的关键点就是
step
这个变量, 它用来控制
mergeArrays()
函数生成的leftArr
和
rightArr
这两个子序列的大小。 通过控制子序列的大小, 处理排序是比较高效的, 因为它在对小数组进行排序时不需要花费太多时间。 合并之所以高效, 还有一个原因,
由于未合并的数据已经是排好序的, 将它们合并到一个有序数组的过程非常容易
测试
var
nums = new CArray(10);
nums.setData();
alert(nums.toString());
nums.mergeSort();
alert(nums.toString());
归并排序的命名来自它的实现原理: 把一系列排好序的子序列合并成一个大的完整有序序列。 从理论上讲, 这个算法很容易实现。 我们需要两个排好序的子数组, 然后通过比较数据大小, 先从最小的数据开始插入, 最后合并得到第三个数组。 然而, 在实际情况中, 归并排序还有一些问题, 当我们用这个算法对一个很大的数据集进行排序时, 我们需要相当大的空间来合并存储两个子数组。 就现在来讲, 内存不那么昂贵, 空间不是问题, 因此值得我们去实现一下归并排序,
比较它和其他排序算法的执行效率。
自底向上的排序方法
采用非递归或者迭代版本的归并排序是一个自底向上的过程。 这个算法首先将数据集分解为一组只有一个元素的数组。
然后通过创建一组左右子数组将它们慢慢合并起来, 每次合并都保存一部分排好序的数据, 直到最后剩下的这个数组所有的数据都已完美排序。 下图演示了自底向上的归并排序算法如何运行的。
代码测试:
1.所调用的函数:
function CArray(numElements) {
this.dataStore = [];
this.toString = toString;
this.numElements = numElements;
this.setData = setData; //随机生成一组数
this.mergeSort=mergeSort;
this.mergeArrays=mergeArrays;
for (var i = 0; i < numElements; ++i) {
this.dataStore[i] = i;
}
}
function setData() {
for (var i = 0; i < this.numElements; ++i) {
this.dataStore[i] = Math.floor(Math.random() *
(this.numElements+1));
}
}
function toString() {
var retstr = "";
for (var i = 0; i < this.dataStore.length; ++i) {
retstr += this.dataStore[i] + " ";
if (i > 0 && i % 10 == 0) {
retstr += "\n";
}
}
return retstr;
}
function mergeSort() {
if (this.dataStore.length < 2) {
return;
}
var step = 1;
var left, right;
while (step < this.dataStore.length) {
left = 0;
right = step;
while (right + step <= this.dataStore.length) {
mergeArrays(this.dataStore, left, left+step, right, right+step);
left = right + step;
right = left + step;
}
if (right < this.dataStore.length) {
mergeArrays(this.dataStore, left, left+step, right, this.dataStore.length);
}
step *= 2;
}
}
function mergeArrays(arr,startLeft, stopLeft, startRight, stopRight) {
var rightArr = new Array(stopRight - startRight + 1);
var leftArr = new Array(stopLeft - startLeft + 1);
k = startRight;
for (var i = 0; i < (rightArr.length-1); ++i) {
rightArr[i] = arr[k];
++k;
} k
= startLeft;
for (var i = 0; i < (leftArr.length-1); ++i) {
leftArr[i] = arr[k];
++k;
}
rightArr[rightArr.length-1] = Infinity; // 哨兵值
leftArr[leftArr.length-1] = Infinity; // 哨兵值
var m = 0;
var n = 0;
for (var k = startLeft; k < stopRight; ++k) {
if (leftArr[m] <= rightArr
) {
arr[k] = leftArr[m];
m++;
}
else {
arr[k] = rightArr
;
n++;
}
}
alert("left array - ", leftArr[m]);
alert("right array - ", rightArr
);
}
说明:函数中的关键点就是
step
这个变量, 它用来控制
mergeArrays()
函数生成的leftArr
和
rightArr
这两个子序列的大小。 通过控制子序列的大小, 处理排序是比较高效的, 因为它在对小数组进行排序时不需要花费太多时间。 合并之所以高效, 还有一个原因,
由于未合并的数据已经是排好序的, 将它们合并到一个有序数组的过程非常容易
测试
var
nums = new CArray(10);
nums.setData();
alert(nums.toString());
nums.mergeSort();
alert(nums.toString());
相关文章推荐
- javascript-知识点集合
- 详解Javascript的继承实现(二)
- 22、Ext.util.JSON.decode 的用法?
- 关于jsp页面page指令中errorpage和iserrorpage属性
- JavaScript提交表单时检查所填是否有效
- Echarts.js遇见的问题(tooltip)
- javascript 收藏本站的代码
- Javascript闭包——懂不懂由你,反正我是懂了
- JavaScript之基础-8 JavaScript 数组(创建、访问、常用方法、二维数组)
- 加载json数据创建控制器
- iOS中的javaScript框架
- JavaScript作用域和执行环境
- JSP中重写404,相关配置
- Javascript的console.log()用法
- javascript学习笔记 - 执行环境及作用域
- 第五天学习javascript
- 在JavaScript中创建命名空间的几种写法
- 改变字体大小实现自适应之js方案A
- jsp
- JavaScript基础回顾(思维导图之JavaScript变量)