排序搜索算法
排序算法
冒泡排序
冒泡排序是比较所有相邻的两个项,如果第一个比第二个大,就交换他们,这是整个排序中时间复杂度最大的一个O(n²)
function swap(array,a,b){
const temp = array[a]
array[a] = array[b]
array[b] = temp
//或者采用ES6
[arrat[a],array[b]]=[array[b],array[a]]
}
function bubbleSort(array){
const {length} = array
for(let i = 0;i<length;i++){
for(let j = 0;j<length-1-i;j++){
if(array[j]>array[j+1]){
swap(array,j,j+1)
}
}
}
return array
}
选择排序
找到结构中的最小值放在前面,然后继续找第二小的,继续排序,同样的,时间复杂度也是O(n²)
//如果出现swap则是使用冒泡排序上的swap函数
function selectSort(array){
const {length} = array
let indexMin
for(let i = 0;i<length-1;i++){
indexMin = i
for(let j = 0;j<length;j++){
if(array[indexMin]>array[j]){
indexMin = j
}
}
if(i!==indexMin){
swap(array,i,indexMin)
}
}
return array
}
插入排序
假定第一项已经排序了,接着跟第二项进行比较是放在原位还是放在第一项前?然后以此类推
function insertionSort(array){
const {length} = array
let temp
for(let i = 1;i<length;i++){
let j = i
temp = array[i]
while(j>0&&array[j-1]>temp){
array[j] = array[j-1]
j--
}
array[j] = temp
}
return array
}
归并排序
将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后一个排序完毕,该排序的时间复杂度是O(nlog(n))
//此函数用于接收两个数组作为参数,并将它们归并到一个大的数组中,完成排序
function merge(left,right){
let i = 0
let j = 0
const result = []
while(i<left.length&&j<right.length){
result.push(left[i]<right[j]?left[i++]:right[j++])
}
return result.concat(i<left.length?left.slice(i):right.slice(j)
}
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)
}
return array
}
快速排序
时间复杂度为O(nlog(n)),这个算法比较复杂,全过程在于:
- 首先从数组中选择一个值作为主元,也就是数组中间的值
- 创建两个指针,左边一个指针指向数组第一个值,右边一个指针指向数组最后一个值。移动左指针直到我们找到第一个比主元大的值,接着移动右指针直到找到比主元小的值,然后交换他们,重复这个过程,直到左指针超过右指针,这个过程使得比主元小的值都排在主元之前,比主元大的都排在主元之后欧,这一步叫划分
- 算法对划分后的小数组重复之前的步骤,直到排序完成
function quickSort(array){
return quick(array,0,array.length-1)
}
function quick(array,left,right){
let index
if(array.length>1){
index = partition(array,left,right)
if(left<index-1){
quick(array,left,index-1)
}
if(index<right){
quick(array,index,right)
}
}
return array
}
function partition(array,left,right){
//首先设置一个主元
const pivot = array[Math.floor((right+left)/2)]
let i = left
let j = right
//只要指针没有相互交错,就开始移动left指针,直到找到一个比主元大的元素,right指针是找到比主元小的
while(i<=j){
while(array[i]<pivot){
i++
}
while(array[j]<pivot){
j++
}
//当左指针指向的元素比主元大且右指针指向的元素比主元小,并且左指针指引没有右指针索引大时,就就换他们位置,然后重新回到前面继续重复
if(i<=j){
swap(array,i,j)
i++
j--
}
}
return i
}
计数排序
这是分布式排序的一种,是使用已组织好的辅助数据结构,进行合并得到排序好的数组,时间复杂度为O(n+k)k为临时计数数组的大小
function findMaxValue(array){
let max = array[0]
for(let i = 0;i<array.length;i++){
if (array[i]>max){
array[i] = max
}
}
return max
}
function countingSort(array){
if(array.length<2){
return array
}
//首先要找到数组的最大值
const MaxValue = findMaxValue(array)
const counts = new Array(maxValue+1)
//先把每个非0的计数位置全部置0,然后迭代数组,在相应的位置计数
array.forEach(element=>{
if(!counts[element]){
counts[element] = 0
}
counts[element]++
})
let sortedIndex = 0
counts.forEach((count,i)=>{
while(count>0){
array[sortedIndex++] = i
count--
}
})
return array
}
分布式算法还有 桶排序
基数排序
的算法方式
搜索算法
顺序搜索
这是最基础也是效率最低的搜索算法,将数据结构中每一个元素和我们要找的元素比较
const DOES_NOT_EXIST = -1
function sequentialSearch(array,value){
for(let i = 0:i<array.length;i++){
if(array[i] = value){
return array[i]
}
}
return DOES_NOT_EXIST
}
二分查找
这个算法要求的是数据结构已经被排序好了,于是会有以下步骤:
- 选择数组中间的值
- 如果选中的值是待搜索值,那么就算找到了
- 如果待搜索值比选中的小,就返回步骤1并在选中的值左边的子数组中寻找
- 如果带搜索的值比选中值大,则返回步骤1并在选中值右边的子数组中寻找
function binarySearch(){
const sortedArray = quickSort(array)
let low = 0
let high = sortedArray.length-1
while(low<high){
const mid = Math.floor((low+high)/2)
const element = sortedArray[mid]
if(element<value){
low = mid+1
}else if(element>value){
high = mid -1
}else{
return mid
}
}
return -1
}
内插搜索
这是改良版本的二分搜索,二分搜索总是检查mid位置上的值,而内插搜索可能会根据要搜索的值检查数组中的不同地方
随机算法
Fisher-Yates算法
迭代数组,从最后一位开始并将当前位置和一个随机位置进行交换,这个随机位置比当前位置小,这样算法可以保证随机过的位置不会再被随机一次
function shuffle(array){
for(let i = array.length-1;i>0;i--){
const randomIndex = Math.floor(Math.random()*(i+1))
swap(array,i,randomIndex)
}
return array
}