js数据结构排序示例教程(全网精简版)
作者:..儒
冒泡排序
function BubbleSort(){ const{length}=array for(let i=0;i<length;i++) { for (let j=0;j<length-1-i;j++){ if(arr[j]>arr[j+1]){ swap(arr,j,j+1) } } } console.log(arry); } function swap(arry, a, b) { const temp = arry[a] arry[a] = arry[b] arry[b] = temp //或者用 [arry[b],arry[a]]=[arry[a],arry[b]]//es6中数组解构 } var arr= [1,2,3,4,5]
选择排序
记录并不断更改索引值,找到最小的数后替换
假设数组为 [5, 3, 8, 4, 2]
:
- 第一轮外部循环(
i = 0
):- 内部循环找到最小元素
2
在索引4
,交换后数组变为[2, 3, 8, 4, 5]
。
- 内部循环找到最小元素
- 第二轮外部循环(
i = 1
):- 内部循环找到最小元素
3
在索引1
(未移动),数组保持不变。
- 内部循环找到最小元素
- 第三轮外部循环(
i = 2
):- 内部循环找到最小元素
4
在索引3
,交换后数组变为[2, 3, 4, 8, 5]
。
- 内部循环找到最小元素
- 第四轮外部循环(
i = 3
):- 内部循环找到最小元素
5
在索引4
,交换后数组变为[2, 3, 4, 5, 8]
。
- 内部循环找到最小元素
排序完成,最终数组为 [2, 3, 4, 5, 8]
。
插入排序
记录索引对于元素的值,就是把大的数往后面覆盖,最后肯定右两个重复的大数,直接把当前的temp覆盖到排在前面的大数就行
function insertSort(){ const {length}=arr let temp for(let i=1;i<length;i++){ temp=arr[i] j=i while(j>0&&arr[j-1]>temp){ arr[j]=arr[j-1] j-- } arr[j]=temp } console.log(arr); } insertSort=[5, 4, 3, 3, 1]
具体用实例说明
第一轮循环(i = 1):
temp = arr[1] = 4
j = 1
- 比较
arr[j-1] (5)
和temp (4)
,因为5 > 4
,所以进入 while 循环。 - 将
arr[j-1]
(5) 后移一位,数组变为[5, 5, 3, 3, 1]
j--
,现在j = 0
- while 循环结束,因为
j = 0
- 将
temp (4)
插入到arr[j]
,数组变为[4, 5, 3, 3, 1]
第二轮循环(i = 2):
temp = arr[2] = 3
j = 2
- 比较
arr[j-1] (5)
和temp (3)
,因为5 > 3
,所以进入 while 循环。 - 将
arr[j-1]
(5) 后移一位,数组变为[4, 5, 5, 3, 1]
j--
,现在j = 1
- 比较
arr[j-1] (4)
和temp (3)
,因为4 > 3
,所以继续 while 循环。 - 将
arr[j-1]
(4) 后移一位,数组变为[4, 4, 5, 3, 1]
j--
,现在j = 0
- while 循环结束,因为
j = 0
- 将
temp (3)
插入到arr[j]
,数组变为[3, 4, 5, 3, 1]
第三轮循环(i = 3):
temp = arr[3] = 3
j = 3
- 比较
arr[j-1] (5)
和temp (3)
,因为5 > 3
,所以进入 while 循环。 - 将
arr[j-1]
(5) 后移一位,数组变为[3, 4, 5, 5, 1]
j--
,现在j = 2
- 比较
arr[j-1] (4)
和temp (3)
,因为4 > 3
,所以继续 while 循环。 - 将
arr[j-1]
(4) 后移一位,数组变为[3, 4, 4, 5, 1]
j--
,现在j = 1
- 比较
arr[j-1] (3)
和temp (3)
,因为3 == 3
,所以 while 循环结束。 - 将
temp (3)
插入到arr[j]
,数组变为[3, 3, 4, 5, 1]
第四轮循环(i = 4):
temp = arr[4] = 1
j = 4
- 比较
arr[j-1] (5)
和temp (1)
,因为5 > 1
,所以进入 while 循环。 - 将
arr[j-1]
(5) 后移一位,数组变为[3, 3, 4, 5, 5]
j--
,现在j = 3
- 比较
arr[j-1] (4)
和temp (1)
,因为4 > 1
,所以继续 while 循环。 - 将
arr[j-1]
(4) 后移一位,数组变为[3, 3, 4, 4, 5]
j--
,现在j = 2
- 比较
arr[j-1] (3)
和temp (1)
,因为3 > 1
,所以继续 while 循环。 - 将
arr[j-1]
(3) 后移一位,数组变为[3, 3, 3, 4, 5]
j--
,现在j = 1
- 比较
arr[j-1] (3)
和temp (1)
,因为3 > 1
,所以继续 while 循环。 - 将
arr[j-1]
(3) 后移一位,数组变为[3, 3, 3, 4, 5]
j--
,现在j = 0
- while 循环结束,因为
j = 0
- 将
temp (1)
插入到arr[j]
,数组变为[1, 3, 3, 4, 5]
归并排序
火狐浏览器的sort就是基于这种排序,chrome用到快速排序
function mergeSort(array){ if(array.length>1){ const {length}=array const middle=Math.floor(length/2) const left=mergeSort(array.slice(0,middle)) const right=mergeSort(array.slice(middle,length)) array=merge(left,right) } } function merge(left,right){ let i=0; let j=0; const result=[] while(i<left.length&&i<right.length){ result.push(left[i]<right[i]?left[i++]:right[i++]) } result.concat(i<left.length?left.slice(i):right.slice(j)) } mergeSort([5,4,3,2,1])
用具体例子解释一下执行过程
第一次调用 mergeSort:
- 数组长度大于 1,继续执行。
middle
是 2。left
是[5, 4]
,right
是[3, 2, 1]
。- 递归调用
mergeSort
对left
和right
进行排序。
merge中执行过程
第一轮比较:left[i] (4)
与right[j] (1)
比较,因为1 < 4
,所以将1
添加到result
中。
第二轮比较:j
增加 1,现在j = 1
。left[i] (4)
与right[j] (2)
比较,因为2 < 4
,所以将2
添加到result
中。
第三轮比较:j
增加 1,现在j = 2
。left[i] (4)
与right[j] (3)
比较,因为3 < 4
,所以将3
添加到result
中。
第四轮比较:j
增加 1,现在j = 3
。left[i] (4)
与right[j] (不存在)
比较,因为right
数组已经没有更多元素,所以将left
数组剩余的元素[4, 5]
添加到result
中。
快速排序
以一个元素为基准(可以是middle,0,length-1)把比它小的放一堆,比它大的放一堆,在以第一堆的元素中挑一个基准,比它大的挑一堆,比它小的调一堆,分到最后把这几堆和一起。
function quickStore(){ const {length}=arr if(length<2){ return arr } let base=arr[0] let minArr=arr.slice(1).filter(item=>item>=base) let maxArr=arr.slick(1).filter(item=>item<base) return quickStore(minArr).contact(base).contact(quickStore(maxArrft)) }
计数排序
但是会占据空间
找到最大值
const maxValue = findMax(arr) // const maxValue = Math.max(...arr)
- 调用
findMax
函数来找到数组中的最大值。 findMax
函数遍历数组,比较每个元素,找到最大值。
:初始化计数数组
const counts = new Array(maxValue + 1)
- 创建一个长度为
maxValue + 1
的数组counts
,用于存储每个元素的出现次数。 - 由于最大值是 9,所以
counts
的长度为 10。: 计数每个元素的出现次数
例如遍历到数组中数字5出现2次,就把counts计数数组的下标为5的位置计为1,再白能力一遍还有就++计为2。所以count数组中索引值为5的地方数值为2,意思是5出现了两次。
arr.forEach(item => { if(!counts[item]){ counts[item] = 0 } counts[item]++ })
构建新的排序数组
let newarr = [] let sortIndex = 0 counts.forEach((item, index) => { while(item > 0){ newarr[sortIndex++] = index item-- } })
- 初始化一个新的空数组
newarr
。 - 遍历
counts
数组,根据计数构建新的排序数组。 - 对于
counts
中的每个非零元素,将其索引(即原数组中的元素值)添加到newarr
中相应次数。例如:遍历到5前面数字都没有出现就不会进入while循环,知道索引值index为5时,就将newarr
中sortIndex=0索引值为0的位置计为index5,sortIndex++变为1,迎接下一个元素,counts
数组中索引值5的item减一也就是减少出现次数后再遍历是否还出现,如果还有就把count下标1的位置再计为5.出现次数减一。 - 完整代码
var arr=[5,7,5,4,9,1] function countSort(arr){ if(arr.length<2){ return arr } const maxValue=findMax(arr) // const maxValue=Math.max(...arr)也可以用js内置方法 const counts=new Array(maxValue+1) arr.forEach(item => { if(!counts[item]){ counts[item]=0 } counts[item]++ }) let newarr=[] let sortIndex=0 counts.forEach((item,index)=>{ while(item>0){ newarr[sortIndex++]=index item-- } }) } countSort(arr) function findMax(arr){ let max=arr[0] for(let i=0;i<length;i++){ if(arr[i]>max){ maax=arr[i] } } return newarr }
桶排序
- 数据稀疏桶会少,数据庞大桶多
function bucketSort(arr, bucketSize=3){ if(arr.length<2){ return arr } //创建几个小桶 const buckets=createBucket(arr,buckdetSize) //小桶排序(插入算法)合并concat return sortBucket(buckets) } function createBucket(arr,buckdetSize){ //找最大值和最小值 let minValue=Math.min(...arr) let maxValue=Math.max(...arr) //桶数量 const bucetCount=Math.floor((maxValue-minValue)/ buckdetSize)+1//+1是为了如果最大值正好等于某个桶的边界值, // 那么按照简单的除法计算,最大值可能会被分配到超出桶的范围之外。 // //创建桶子 // const buckets = [] // for (let i = 0; i < bucketCount; i++) { // buckets[i] = [] // } // ES6 const buckets=[...Array(bucetCount)].map(()=>[]) //判断每个元素应该进哪个桶子 for (let i = 0; i < arr.length; i++) { const index = Marh.floor((arr[i] - minValue) / bucketSize) buckets[index].push(arr[i]) } return buckets } function sortBucket(){ const sortArr=[] for(let i=0;i<arr.length;i++){ if(arr[i]){ insertSort(arr[i]) sortArr.push(...arr[i]) } } } function insertSort() { const { length } = arr let temp for (let i = 1; i < length; i++) { temp = arr[i] j = i while (j > 0 && arr[j - 1] > temp) { arr[j] = arr[j - 1] j-- } arr[j] = temp } console.log(arr); } bucketSort([5,4,3,2,6,1,7,10,9,8])
缺点是如果最大数为100,中间会创造很多无效桶
基数排序
填补了计数排序和桶排序的缺点
给定桶子的数量。一般是10,将数组里的数字先按照个位排序,再按十位,再百位~
再掌握这个思想
//Math.floor(x/diveder)%base //divider*=base
以35举例:x是35,diveder事先定义为1,base为10
得到十位35/1=35%10=5,得到个位35/10=3%10=3
let maxVal=Math.max(...arr) while(divider<=maxVal){ //构建二维数组 const buckets = [...Array(10)].map(() => []) for (let val of arr) { buckets[Math.floor(val / divider) % base].push(val) //把取得个位数,十位数百位数推到bukets中 } arr = [].concat(...buckets) divider *= base }
去最大值作为循环结束的条件
用array和map的方法创建10个空数组。遍历arr中元素,用Math方法取出个十百位数,推到buckets中,如:bucket[3]=3
arr = [].concat(...buckets) divider *= base
表示将arr数组中所有个位数取出来排好后,用concat连成数组,再排新数组中每个元素的十位数,divider*10后变成10.....
完整代码
const arr=[35,2,26,2,5,8,34,1,56,99,33] function radixSort(arr){ const base=10 let divider=1 //Math.floor(x/diveder)%base//得到十位35/1=35%10=5,得到个位35/10=3%10=3 //divider*=base let maxVal=Math.max(...arr) while(divider<=maxVal){ //构建二维数组 const buckets = [...Array(10)].map(() => []) for (let val of arr) { buckets[Math.floor(val / divider) % base].push(val)//把取得个位数,十位数百位数推到bukets中 } arr = [].concat(...buckets) divider *= base } return arr }
总结
到此这篇关于js数据结构排序的文章就介绍到这了,更多相关js数据结构排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!