数组测试平台
首先从一个数组类开始,我们不适用原生的Array,在自定义的数组类中定义一些方法来适应本章的排序内容
function myArr(num) {
this.dataStore = []
this.numElements = num
this.pos = 0
}
myArr.prototype = {
insert: function(element) {
this.pos ++
this.dataStore.insert(element)
},
clear: function() {
this.dataStore = []
},
setData: function() {
for(var i = 0; i< this.numElements; i++) {
this.dataStore.push(Math.floor(Math.random()* (this.numElements+1)))
}
},
show: function() {
return this.dataStore
},
swap: function(arr, index1, index2) {
var temp = arr[index1]
arr[index1] = arr[index2]
arr[index2] = temp
}
}
var nums = 100
var myNums = new myArr(nums)
myNums.setData()
myNums.show()
几种基本的排序方法(默认升序)
冒泡排序
思路: 循环遍历数组,如果当前i比i+1位置的值大则互换位置,每次得到固定的最后一位, 例如一个 43215 第一次循环i=0
- 34215
- 32415
- 32145 此时5为固定位置,下次循环只需要循环5-1次
BubleSort: function() {
for(var i = 0; i< this.dataStore.length; i++) {
for(var j = 0; j< this.dataStore.length - i; j++) {
// console.log(i,j)
if(this.dataStore[j] > this.dataStore[j+1]) {
this.swap(this.dataStore, j, j+1)
}
}
}
console.log(this.dataStore)
},
选择排序
思路: 每次找到最小的数字排在当前第i位置
SelectionSort:
function() {
for(var i = 0; i< this.dataStore.length; i++) {
for(var j = i; j< this.dataStore.length; j++) {
if(this.dataStore[j] < this.dataStore[i]) {
this.swap(this.dataStore, i, j)
}
}
}
console.log(this.dataStore)
}
插入排序
思路
- 从一个元素开始,认为这个元素已经被排序
- 取下一个元素,在已经排序的元素中从后向前扫描
- 如果这个元素大于新元素,将该元素移动到下一个位置
- 重复上一步,直到这个元素找到小于等于新元素的位置
InsertSort: function () {
for (let i = 1; i < this.dataStore.length; i++) {
for (let j = i; j > 0; j--) {
if (this.dataStore[j - 1] > this.dataStore[j]) {
this.swap(this.dataStore, j - 1, j)
}
}
}
console.log(this.dataStore)
}
时间复杂度 o^2 三种算法没有明显的差异
高级的排序算法
希尔排序
希尔排序提出一个间隔序列,来表示在排序过程中进行比较的元素有多远的间隔 有一些公开定义的间隔,2001年 MarcinCiura 提出间隔701,301,57,23,10,4,1
shellSort: function() {
for(var g=0; g< this.gaps.length; ++g) {
for(var i= this.gaps[g]; i< this.dataStore.length; i++ ) {
var temp = this.dataStore[i]
for(var j = i; j>=this.gaps[g] && (this.dataStore[j-this.gaps[g]] > temp); j -= this.gaps[g]) {
this.dataStore[j] = this.dataStore[j - this.gaps[g]]
}
this.dataStore[j] = temp
}
}
}
动态设置间隔 根据研究得出结果
var N = this.dataStore.length
var h = 1
if(h*3< N) {
h = 3*h - 1
}
shellSort1: function () {
var N = this.dataStore.length
var h = 1
while (h < N/3) {
h = 3 * h + 1
}
while(h >= 1) {
for( var i = h; i< N; i++) {
for(var j = i; j >= h && this.dataStore[j] < this.dataStore[j-h]; j-=h) {
this.swap(this.dataStore, j, j-h)
}
}
h = (h-1) / 3
}
console.log(this.dataStore)
}
归并排序
归并排序: 把一系列排序好的子序列合并成一个大的完善的有序序列,从理论上来讲,我们需要两字拍好的子数组,然后通过比较数据大小,最小的开始插入,最后合并得到第三个数组。而实际中,我们对一个很大的数据集进行排序时,我们需要相当大的空间来存储和合并这两个子数组。所以当内存不昂贵,空间不是问题时,我们值得使用归并排序。
- 自顶向下的归并排序
- 自顶向上的归并排序
mergeSort: function (arr) {
if (arr.length < 2) {
return
}
var step = 1
var left, right
while (step < arr.length) {
left = 0
right = step
while (right + step <= arr.length) {
this.mergeArr(arr, left, left + step, right, right + step)
left = right + step
right = left + step
}
if (right < arr.length) {
this.mergeArr(arr, left, left + step, right, arr.length)
}
step *= 2
}
},
mergeArr(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[n]) {
arr[k] = leftArr[m]
m++
} else {
arr[k] = rightArr[n]
n++
}
}
}
有点巧妙啊。。
快速排序
最快的排序算法之一,选择一个基准元小于基准元移到底部,大于则遇到顶部 下面是排序过程演示
44, 75, 23, 43, 55, 12, 64, 77, 33
原始数组以44为基准元
23, 12, 33, 43, 44, 75, 55, 64, 77
分成两个子数组
23,12 43,33 75,55 64,77
按照基准元分组
12,23 33,43, 55,75, 64,77
每个组进行排序
步骤
- 选择一个基准元, 将列表分割为两个序列
- 对其排序,小于基准元放在一个数组,大于放在另一边
- 两个子序列重复1,2 步骤