排序算法的Javascript实现
1.冒泡排序:
比较相邻的两个数,如果前一个数大于后一个数,就将这两个数换位置。每一次遍历都会将本次遍历最大的数冒泡到最后。为了将n个数排好序,需要n-1次遍历。 如果某次遍历中,没有调整任何两个相邻的数的位置关系,说明此时数组已排好序,可以结束程序。
Array.prototype.bubbleSort = function () { let i, j; for (i = 1; i < this.length; i++) { //表示本次是第i次遍历 let changed = false; for (j = 0; j < this.length - i; j++) { //访问序列为arr[0:length-i] if(this[j] > this[j + 1]){ //发现前一个数大于后一个时,互换位置 [this[j],this[j+1]] = [this[j+1],this[j]]; changed = true; } } if(!changed) { //如果本轮遍历没有发现位置调整,结束排序函数 break; } } }; let arr = [43, 21, 10, 5, 9, 15, 32, 57, 35]; arr.bubbleSort(); console.log(arr);
2.选择排序
第i轮遍历arr[0:n-i]选出最大的数,与arr[n-i]互换。
Array.prototype.selectSort = function () { let i, j; for (i = 1; i < this.length; i++) { //表示本次是第i次遍历 let maxIndex = 0; for (j = 0; j <= this.length - i; j++) { //访问子序列为arr[0:this.length-i] if (this[j] > this[maxIndex]) { //当前值大于当前最大值时,记录索引 maxIndex = j; } } //将子数组最大值索引的值,与子数组末尾的值互换 [this[this.length - i], this[maxIndex]] = [this[maxIndex], this[this.length - i]] } }; let arr = [43, 21, 10, 5, 9, 15, 32, 57, 35]; arr.selectSort(); console.log(arr);
3.插入排序 数组的前面部分已经排好序,要把当前数字插入到前面已排好序的数组的相应位置。可能有人会有疑问为什么默认数组前面部分已排好序?是怎么排好序的?是因为当排序开始时,从第2个数字开始进行向前插入,此时当前数字索引为1,当前数字前面仅有一个数字,因此可以认为前面部分已经排好序,将这个数字插入到相应位置之后数组仍然是有序的。每次都将当前数字插入到对应的位置,因此每次插入之后前面的数组仍是排好序的。
Array.prototype.insertSort = function () { let i, j; for (i = 1; i < this.length; i++) { //i表示当前要向前插入的数字的索引,从1(即第2个数)开始前插 let val = this[i]; //记录当前要前插的数的大小 /* * 用指针j来遍历第i个数字前面的,已经排好序的子数组。当j没有指到头,并且j的数字大于要插入的数字时,说明 * j还要向前遍历,直到发现一个比要插入数字小的位置pos,然后将这个数字插到pos+1处。如果j已经指到头了, * 到了-1了还没有找到比当前数字小的位置,就把当前数字放在索引0处。 * */ for (j = i - 1; j >= 0 && this[j] > val; j--) { this[j + 1] = this[j]; } this[j + 1] = val; } }; let arr = [43, 21, 10, 5, 9, 15, 32, 57, 35]; arr.insertSort(); console.log(arr);
4.shell排序 加了step的插入排序。分别以索引数为0,1,......step-1的元素为起点,将其看做不同的组,0、0+step,0+2step,......,0+nstep为一组,1,1+step,1+2step,.....,1+nstep为一组依次分组,按照组为单位进行插入排序。各组都已经插入排序一轮过后,将step除以2向下取整,再进行分组并将各组分别进行插入排序,直到step为0。 step的取值与性能直接相关,需要思考后取值。 并且这里的分组仅仅是逻辑上分组,并没有开辟新的地址空间将其进行物理上的分组。
const {floor} = Math; //这个和插入排序相同,只不过加了step Array.prototype.shellInsertSort = function (startIndex, step) { let i, j; for (i = startIndex + step; i < this.length; i += step) { let val = this[i]; for (j = i - step; j >= 0 && this[j] > val; j -= step) { this[j + step] = this[j]; } this[j + step] = val; } }; Array.prototype.shellSort = function () { let i, step; for (step = floor(this.length / 2); step > 0; step = floor(step / 2)) { for (i = 0; i < step; i++) { this.shellInsertSort(i, step); } } }; let arr = [43, 21, 10, 5, 9, 15, 32, 57, 35]; arr.shellSort(true); console.log(arr);
5.合并排序
举个例子: 有 43 12 32 29 66 78 31这个数组要用合并排序。 先将相邻两数分为一组进行合并 43|12 32|29 66|78 31 结果为12 43 29 32 66 78 31
再将组的大小乘以二 (12 43|29 32) (66 78|31) 本次合并后结果为 12 29 32 43 31 66 78
再将组的大小乘以二 12 43 29 32 | 66 78 31 合并结果:12 29 31 32 43 66 78
合并的过程中要开辟新的数组arr,建立两个指针i,j分别指向arr1与arr2,此时arr1与arr2都是排好序的,然后每次都将arr1[i]与arr2[j]较小的数加到arr中并将指针后移。最后哪个数组有剩余的数在追加到arr后面。
相关推荐
要知道时间复杂度只是描述一个增长趋势,复杂度为O的排序算法执行时间不一定比复杂度为O长,因为在计算O时省略了系数、常数、低阶。实际上,在对小规模数据进行排序时,n2的值实际比 knlogn+c还要小。