1、选择排序
//给一堆,每次从剩下的元素中间挑最小的和当前元素(i对应的)去比,若更小则交换
const arr =[911,520,888,666,555,2323];
function chooseSort(arr){
let minIndex;
let temp;//当前值,用于交换
for(let i=0;i<arr.length;i++){//遍历每个位置
//从剩下元素中找最小的(比当前元素更小的)
minIndex=i;//初始最小下标设置为当前元素
for(let j=i+1;j<arr.length;j++){
if(arr[j]<arr[minIndex]){
minIndex=j;//记录最小元素下标
}
}
//找完了,交换i和minIndex
temp=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
return arr
}
console.log(chooseSort(arr))
2、插入排序
function insertSort(arr){
//进行插入排序
let temp;//当前值,用于交换
//第一个元素肯定有序
for(let i=1;i<arr.length;i++){//遍历每个位置
temp=arr[i];
//找i前面的
let j=i-1;
for(;j>=0;j--){
//大于的则挪
if(arr[j]>temp){
//依次把元素往后挪,
arr[j+1]=arr[j];
console.log(arr[j+1])
}else{
break;
}
}
arr[j+1]=temp;//插入把当前元素插入到该放的位置
}
}
const arr =[911,520,888,666,555,2323];
insertSort(arr,3);
console.log(arr)
3、归并排序
//两个有序数组的合并排序//依次遍历两个有序数组的元素进行比较,排序
const arrS=[1,3,5,7,2,4,6];
function mergeScopedSort(arrS,statr1,end1,start2,end2,newArr){
let i=statr1;
let j=start2;
let index=statr1;//新数组下标
while(i<=end1&&j<=end2){
if(arrS[i]<=arrS[j]){
newArr[index++]=arrS[i++];
}else{
newArr[index++]=arrS[j++];
}
}
//注意有些数组结束要把剩下的加进来
while(i<=end1){
newArr[index++]=arrS[i++];
}
while(j<=end2){
newArr[index++]=arrS[j++];
}
//把statr1,end1,start2,end2的元素拷贝到原容器
for(let i=0;i<arrS.length;i++){
if(newArr[i]!==undefined){
arrS[i]=newArr[i]
}
}
}
/*//测试第一个函数
const newArrS=new Array(arrS.length);
mergeScopedSort(arrS,0,3,4,6,newArrS)
console.log(newArrS)*/
//一个元素肯定有序
//把每单个元素当作一组必定有序,再合并成两两一组有序,再接着依次类推
//使用递归是从大到小
function mergeSort(arr,left,right,newArr){
//递归结束
if(left>=right){
return;
}
let mid=parseInt((left+right)/2);
mergeSort(arr,left,mid,newArr);//排序左边
mergeSort(arr,mid+1,right,newArr);//排序右边
//再合并两边
mergeScopedSort(arr,left,mid,mid+1,right,newArr);
}
const arr =[911,520,888,666,555,2323];
const newArr=new Array(arr.length);//新数组装排序后的数组,避免更改原数组导致频繁交换
mergeSort(arr,0,arr.length-1,newArr)
console.log(newArr)
4、希尔排序
//分组排序
//间隔gap的分为一组,第一步间隔为总长度的一半,组内排序(交换)//重新设置分组间隔,间隔减半(gap初始值可任取重设时也可以任意规则)
//间隔为1时进行插入排序,
//希尔排序就是对插入排序的改良,因为元素少和基本有序的时候插入排序的效率更高
//最本质的原因,就是在序列比较多的时候,效率比较高,交换次数和比较次数相对较少
function ShellSort(arr,initGap){
let gap=initGap;
let temp;//当前值,用于交换
while(gap>1){
gap=parseInt(gap/2);
//对每一组进行插入排序
//第一个元素肯定有序
for(let i=gap;i<arr.length;i++){//遍历每个位置
temp=arr[i];
//找i前面的
let j=i-gap;
for(;j>=0;j=j-gap){
//大于的则挪
if(arr[j]>temp){
//依次把元素往后挪,
arr[j+gap]=arr[j];
}else{
break;
}
}
arr[j+gap]=temp;//插入把当前元素插入到该放的位置
}
}
}
const arr =[911,520,888,666,555,2323];
ShellSort(arr,4);
console.log(arr);
5、冒泡排序
//相邻两个元素从头到尾比,根据条件选择是否交换
const arr =[911,520,888,666,555,2323];
function bubbleSort(arr){
let temp;
//i是循环次数(因为最后还剩一个时不用对比,n-1,n-2,...,1),j是指针(每次都是相邻的两个元素对比)
for(let i=0;i<arr.length-1;i++){
// for(j=0;j<arr.length-1;j++){
//优化
for(j=0;j<arr.length-1-i;j++){
//先把最大弄最后,接着第二大,第三大等等
if(arr[j]>arr[j+1]){
//相邻两个元素比较交换
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr
}
console.log(bubbleSort(arr))
6、快速排序
//二分法
const arr =[911,520,888,666,555,2323];
function quickSort(arr){
if(arr.length<2){
return arr;//结束递归
}
let basisIndex=parseInt(arr.length/2);//基准
const left=[];
const right=[];
for(let i=0;i<arr.length;i++){
if(i!=basisIndex){
if(arr[i]<arr[basisIndex]){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
}
return quickSort(left).concat([arr[basisIndex]],quickSort(right))
}
console.log(quickSort(arr))//这里写的函数未改变原数组
console.log(arr)
7、计数排序
function countSort(arr){
let min=arr[0];
let max=arr[0];
//遍历得到数组的最大值和最小值
for (let i = 0; i < arr.length; ++i)
{
if (arr[i] > max){max = arr[i];}
if (arr[i] < min){min = arr[i];}
}
let range=max-min+1;//数组中元素的范围
let count=new Array(range).fill(0);
//计数
for (let i = 0; i < arr.length; ++i)
{
count[arr[i]-min]++;
}
//根据计数数组排序
let i=0;
for(let j=0;j<range;j++){
while(count[j]--){
arr[i++]=j+min;
}
}
}
const arr =[911,520,888,666,555,2323];
countSort(arr)
console.log(arr)
8、堆排序
//堆排序(HeaoSort)是基于数据结构堆设计的一种排序算法,通过堆来选择数据,向上(向下)调整,得到小数(大数),然后再与堆底数据进行交换,即可排序,
//需要注意的是排升序建大堆,排降序建小堆
function swap(arr,childrenIndex,parentIndex){
let temp=arr[childrenIndex];
arr[childrenIndex]=arr[parentIndex];
arr[parentIndex]=temp;
}
//根据数组建大堆
//1堆中节点的向下调整算法
//最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
function adjustDown(arr,startRoot,n){
let parentIndex=startRoot;
let childrenIndex=parentIndex*2+1;//左子节点在数组中对应的下标
while(childrenIndex < n){
if(childrenIndex+1<n&&arr[childrenIndex+1]>arr[childrenIndex]){
childrenIndex++;//找到子节点中最大的节点
}
//判断子节点和父节点谁大
if(arr[childrenIndex]>arr[parentIndex]){
swap(arr,childrenIndex,parentIndex);
parentIndex=childrenIndex;
childrenIndex=parentIndex*2+1;
}else{
break;
}
}
}
function heapSort(arr){
let n=arr.length;
//建最大堆 //这里元素的索引是从0开始的,所以最后一个非叶子结点array.length/2 - 1
//从最后一个父亲节点遍
for(let i = parseInt((n - 1 - 1) / 2); i >= 0; --i){
adjustDown(arr,i,n);//调整堆(调整为当前节点和其后面的节点符合最大堆)
}
//得到最大堆后,进行排序
for (let j = arr.length - 1; j > 0; j--) {
// 把最大堆的根元素,放到数组的最后;
//换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置
swap(arr, 0, j);//每次得到一个第n-j大元素放在数组后面响应的位置
// 最大元素放到最后之后,要对当前堆中(除最后一个),进行最大堆值调整
adjustDown(arr, 0, j);
}
return arr;
}
const arr =[911,520,888,666,555,2323];
heapSort(arr);
console.log(arr)
总结和比较:各种排序算法的时间复杂度和空间复杂度