class ArrayList { constructor() { this.array = [] } insert (...item) { this.array.push(...item) } toString () { return this.array.join() } // 冒泡排序: 比较两个相邻的项,如果第一个大于第二个则交换他们的位置,元素项向上移动至正确的顺序,就好像气泡往上冒一样 // 排序小型数组时,此算法比选择排序和冒泡排序性能要好 算法复杂度O(n^2) bubbleSort () { let i, j, len = this.array.length for (i = 0; i < len; i++) { for (j = i; j < len; j++) { if (this.array[i] > this.array[j]) { [this.array[i], this.array[j]] = [this.array[j], this.array[i]] } } } } // 选择排序:大概思路是找到最小的放在第一位,找到第二小的放在第二位,以此类推 算法复杂度O(n^2) selectionSort () { let i, j, minIndex, len = this.array.length for (i = 0; i < len; i++) { minIndex = i for (j = i; j < len; j++) { if (this.array[j] < this.array[minIndex]) { minIndex = j } } if (minIndex !== i) { [this.array[i], this.array[minIndex]] = [this.array[minIndex], this.array[i]] } } } // 插入排序:每次排一个数组项,假设数组的第一项已经排序,接着,把第二项与第一项进行对比,第二项是该插入到第一项之前还是之后,第三项是该插入到第一项之前还是第一项之后还是第三项 insertionSort () { let i, j, temp, len = this.array.length for (i = 1; i < len; i++) { temp = this.array[i] j = i while (j > 0 && temp < this.array[j -1]) { // 判定一下temp如果小于前面的项 this.array[j] = this.array[j - 1] // 则把所有大于temp的项整体往后移动一位 j-- } this.array[j] = temp // 把temp放在往后移动0到多个项后的空缺位置 } } // 归并排序:Mozilla Firefox 使用归并排序作为Array.prototype.sort的实现,而chrome使用快速排序的一个变体实现的,前面三种算法性能不好,但归并排序性能不错 算法复杂度O(nlog^n) // 归并排序是一种分治算法。本质上就是把一个原始数组切分成较小的数组,直到每个小数组只有一个位置,接着把小数组归并成较大的数组,在归并过程中也会完成排序,直到最后只有一个排序完毕的大数组 mergeSort () { function mergeSortRec(array) { let len = array.length if (len === 1) { return array } let mid = len >> 1, left = array.slice(0, mid), right = array.slice(mid, len) return merge(mergeSortRec(left), mergeSortRec(right)) } // 归并 function merge(left, right) { let arr = [], il = 0, ir = 0 while (left.length > il && right.length > ir) { if (left[il] < right[ir]) { arr.push(left[il]) il++ } else { arr.push(right[ir]) ir++ } } while (left.length > il) { arr.push(left[il]) il++ } while (right.length > ir) { arr.push(right[ir]) ir++ } return arr } this.array = mergeSortRec(this.array) } // 快速排序 算法复杂度O(nlog^n) 通常性能比其他的算法复杂度为O(nlog^n)的性能要好,快速排序也使用分治的方法,将原始数组分为较小的数组(但它并没有像归并一样把数组分割开) // 1) 首先,在数组中选择一个中间项作为主元 // 2) 创建两个指针,左边的只想数组第一个项,右边的指向最后一个项,移动左指针,直到找到一个比主元大的项,接着,移动右边的指针,直到找到一个比主元小的项,然后交换它们。重复这个过程,直到 // 左侧的指针超过了右侧的指针。这个使比主元小的都在左侧,比主元大的都在右侧。这一步叫划分操作 // 3) 接着,算法对划分后的小数组(较主元小的值组成的的小数组, 以及较主元大的值组成的小数组)重复之前的两个步骤,直到排序完成 quickSort () { function quick(array, left ,right) { if (array.length > 1) { let index = partition(array, left ,right) if (left < index -1) { quick(array, left, index -1) } if (index < right) { quick(array, index, right) } } } function partition(array, left, right) { let mid = array[left + right >> 1] // 注意主元的位置可能会变动,先记录主元的值 while (left <= right) { while (array[left] < mid) { left++ } while (array[right] > mid) { right-- } if (left <= right) { [array[left], array[right]] = [array[right], array[left]] left++ right-- } } return left } quick(this.array, 0, this.array.length - 1) } //堆排序:堆排序把数组当中二叉树来排序而得名。 // 1)索引0是树的根节点;2)除根节点为,任意节点N的父节点是N/2;3)节点L的左子节点是2*L;4)节点R的右子节点为2*R + 1 // 本质上就是先构建二叉树,然后把跟节点与最后一个进行交换,然后对剩下对元素进行二叉树构建,进行交换,直到剩下最后一个 heapSort () { function heapify(array, heapSize, i) { let left = i * 2, right = i * 2 + 1, largest = i if (left < heapSize && array[largest] < array[left]) { largest = left } if (right < heapSize && array[largest] < array[right]) { largest = right } if (i !== largest) { [array[i], array[largest]] = [array[largest], array[i]] heapify(array, heapSize, largest) } } function buildHeap(array) { let heapSize = array.length, i for (i = heapSize >> 1; i--;) { heapify(array, heapSize, i) //通过倒叙的方式把最大值放在第一位 console.log(array) } } let heapSize = this.array.length buildHeap(this.array) while (heapSize > 1) { heapSize-- [this.array[0], this.array[heapSize]] = [this.array[heapSize], this.array[0]] heapify(this.array, heapSize, 0) // 在上一次中,只交换来一个,所以只排一次就可以成为二叉树 } } // 分布式排序:原始数据会分发到多个中间结构(桶),再合起来放回原始数组,最著名的分布式排序算法有计数排序,桶排序,基数排序,三种算法非常类似. } let arrayList = new ArrayList arrayList.insert(3, 5, 1, 6, 4, 7, 2) arrayList.heapSort() console.log(arrayList.toString())
es6实现冒泡排序,选择排序,插入排序,归并排序,快速排序,桶排序
最新推荐文章于 2023-05-19 18:59:30 发布