js实现八种排序算法


排序

  • 排序分为内部排序和外部排序。内部排序只使用内存,外部排序使用内存+外存,先加载一部分进行排序再加载一部分
  • 内部排序又分为冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、基数排序和堆排序
  • 时间复杂度
    • 衡量算法程序的执行时间

    • 时间频度

      • 可以忽略常数项
      • 可以忽略低次项
      • 可以忽略系数
    • 常见算法时间复杂度

      • O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)

      • 常数阶O(1)

        • 无论代码执行多少行只要没有复杂的循环结构时间复杂度都是O(1)
        var i=1,j=2;
        ++i;j++;
        var m=i+j;
        
      • 对数阶O(logn)

        	var i=0,n=50;
        	while(i<n){
        		i =i*2;
        	}
        
      • 线性阶O(n)

        	for(let i=0;i<n;i++){
        		console.log("0");
        	}
        
      • 线性对数阶

        	for(let i=0;i<n;i++){
        		var j=1;
        			while(j<n){
        				j =j*2;
        			}
        	}
        
    • 平方阶O(n²) 双重for循环

    • 立方阶、k次方阶多重for循环

    • 平均时间复杂度、最坏时间复杂度
      在这里插入图片描述

冒泡排序

  • 从左到右,一次比较相邻元素的大小
  • 实现思路
    • 共进行数组长度减一次循环
    • 每一趟比较次数递减
    • 可以进行优化,若某次排序未发生交换即可提前结束
  • 冒泡排序图示(3 9 -1 10 20)
    在这里插入图片描述
  • 代码实现
			var arr = [-5,5,3,0,8,-9];
			function bubbleSort(arr){
				var flag=false;
				for(let i=0;i<arr.length-1;i++){
					flag=false;
					for(let j=0;j<arr.length-i-1;j++){
						if(arr[j]>arr[j+1]){//如果前一个比后一个大则交换
							let temp = arr[j];
							arr[j]=arr[j+1];
							arr[j+1]=temp;
							flag=true;
						}
					}
					if(flag==false){
						break;
					}
				}
			}
			bubbleSort(arr);
			console.log(arr);

选择排序

  • 选取某个元素,与后面的元素中寻找是否比它小(或大)的,若有则进行交换
  • 实现思路
    • 选择排序共要进行数组长度减一次排序
    • 每次排序先假定这个数是最小数,然后依次和后面的元素进行比较,发现有更小的数就记录值和下标,直至扫描完,交换
  • 选择排序图示
    在这里插入图片描述
  • 代码实现
			var arr = [8,3,2,1,7,4,6,5];
			function selectSort(arr){
				var index;
				var value;
				for(let i=0;i<arr.length-1;i++){
					index=i;
					value=arr[i];
					for(let j=i+1;j<arr.length;j++){
						if(arr[j]<value){
							index=j;
							value=arr[j];
						}
					}
					let temp = arr[index];
					arr[index]=arr[i];
					arr[i]=temp;
				}
			}
			selectSort(arr);
			console.log(arr);

插入排序

  • 将要排序的数组依次插入临时的数组中,并且插入时要比较该元素与临时数组中元素的大小

  • 插入排序图示
    在这里插入图片描述

  • 代码实现

						var arr=[8,3,2,1,7,4,6,5];
			function insert(num,arr){
				var i;
				for(i=0;i<arr.length;i++){
					if(arr[i]>=num){
						break;
					}
				}
				if(i<arr.length){//证明数组中有元素比num大,num可以插入到数组中
					arr.push(arr[arr.length-1]);//将最后一个元素往后推一个
					for(let j=arr.length-2;j>=i;j--){
						arr[j+1]=arr[j];
					}
					arr[i]=num;
				}else{
					arr.push(num);//将元素放在数组最后
				}
			}
			function insertSort(arr){
				var arr1 = [];
				arr1[0]=arr[0];
				for(let i=1;i<arr.length;i++){
					insert(arr[i],arr1);
				}
				return arr1;
			}
			var arr1=insertSort(arr);
			console.log(arr1);

希尔排序

  • 希尔排序是更高效的插入排序
  • 处理方式
    • 把记录按下表的一定增量分组,对每组进行插入算法排序随着增量减小,每组包含的值越来越多,当增量变为1时,整个数组变成一个,算法终止
  • 希尔排序图示

在这里插入图片描述

  • 代码实现
			var arr=[8,3,2,1,7,4,6,5,9,0];

			function shellSort(arr){
				var step =arr.length;
				while(step){
					for(let i=step;i<arr.length;i++){
						for(let j=i-step;j>=0;j-=step){
							if(arr[j]>arr[j+step]){
								let temp = arr[j];
								arr[j]=arr[j+step];
								arr[j+step]=temp;
							}
						}
					}
					step=parseInt(step/2);
				}
			}
			shellSort(arr);
			console.log(arr)

但是这样实现,仍然存在问题,这样实现的希尔排序交换次数过多,可能会导致比插入排序还要浪费时间,所以,有了以下的代码优化

			var arr=[8,3,2,1,7,4,6,5,9,0];
			function shellSort(arr){
				var step =arr.length;
				while(step){
					for(let i=step;i<arr.length;i++){
						let j=i;
						let value=arr[i];
						if(arr[j]<arr[j-step]){
							while(j-step>=0&&value<arr[j-step]){
								arr[j]=arr[j-step];
								j-=step;
							}
							arr[j]=value;
						}
					}
					step=parseInt(step/2);
				}
			}
			shellSort(arr);
			console.log(arr)

快速排序

  • 对冒泡排序的改进
  • 实现思路
    • 通过一趟排序将要排序的数据分隔为独立的两部分,其中一部分的数据比比某个数据都要小,另一部分比某个数据都要大,然后根据此方法进行递归,直至数组被排完序
  • 快速排序的图示

在这里插入图片描述

  • 代码实现
			var arr=[8,3,2,1,7,4,6,5,9,0];
			function quickSort(arr,left,right){
				var l=left;
				var r=right;
				var index=parseInt((l+r)/2);
				var center=arr[index];
				while(l<r){
					while(arr[l]<center){l++;}
					while(arr[r]>center){r--;}
					if(l>=r){break;}//证明左边已经都小于center,右边也都已经都大于center了
					let temp = arr[l];
					arr[l]=arr[r];
					arr[r]=temp;
					if(arr[l]==center){r--;}
					if(arr[r]==center){l++;}
				}
				if(l==r){
					l++;r--;
				}
				if(left<r){quickSort(arr,left,r);}
				if(l<right){quickSort(arr,l,right);}
			}
			quickSort(arr,0,arr.length-1)
			console.log(arr)

另一种思路,以第一个数据为参照

			var arr=[8,3,2,1,7];
			function quickSort(arr,start,end){
				var key;
				var k;
				var i,j;
				i = start;
				j = end;
				key=arr[i];//以第一个数为基准,将该数组分为小于它的一部分,和大于它的一部分
				while(i<j)
				{
					while(i<j&&arr[j]>key) j--;
					arr[i]=arr[j];
					while(i<j&&arr[i]<=key) i++;
					arr[j]=arr[i];
				}
				arr[i]=key;
				k = i;
				//start位置为基准,对其左右进行递归
				if(start<k) {
					quickSort(arr,start,k-1);
				}
				if(end>k) {
				quickSort(arr,k+1,end);
				}
			}
			quickSort(arr,0,arr.length-1)
			console.log(arr)

归并排序

  • 采用分治策略,将大问题分为小问题,先解决小问题再递归解决大问题
  • 归并排序图示
    在这里插入图片描述
  • 代码实现
			var arr=[8,3,2,1,7,4,6,5,9,0];
			function merge(arr,left,right,mid){
				var i=left;
				var j=mid+1;
				var temp=[];
				var t=0;
				while(i<=mid&&j<=right){
					if(arr[i]<=arr[j]){
						temp[t++]=arr[i++];
					}else{
						temp[t++]=arr[j++];
					}
				}
				while(i<=mid){
					temp[t++]=arr[i++];
				}
				while(j<=right){
					temp[t++]=arr[j++];
				}
				var templeft=left;
				for(let i=0;i<t;i++){
					arr[templeft++]=temp[i];
				}
			}
			function mergeSort(arr,left,right){
				if(left<right){
					var mid = parseInt((left+right)/2);
					mergeSort(arr,left,mid);
					mergeSort(arr,mid+1,right);
					merge(arr,left,right,mid);
				}
			}
			mergeSort(arr,0,arr.length-1);
			console.log(arr);

基数排序

  • 基数排序是桶排序的扩展
  • 基数排序是效率高的稳定的排序方法,经典的空间换时间
  • 基本思想
    • 将所有待比较的数统一为同样地长度,数位较短的前面补零,然后从低位开始一次桶排序
  • 基数排序图示在这里插入图片描述
  • 代码实现
			var arr=[53,3,542,748,14,214];
			function radixSort(arr){
				var tempArr=new Array(10);
				for(let i=0;i<10;i++){
					tempArr[i]=[];
				}
				
				var max = arr[0];
				for(let i=1;i<arr.length;i++){
					if(arr[i]>max){
						max=arr[i];
					}
				}
				max=max+"";
				var times=max.length;
				// var times=0;
				// while(max){
				// 	max=parseInt(max/10);
				// 	times++;
				// }
				var tens=1;
				while(times--){
					for(let i=0;i<10;i++){
						tempArr[i]=[];
					}
					for(let i=0;i<arr.length;i++){
						let index = parseInt(arr[i]/tens)%10;
						tempArr[index].push(arr[i]);
					}
					tens*=10;
					var t=0;
					for(let i=0;i<10;i++){
						for(let j=0;j<tempArr[i].length;j++){
							arr[t++]=tempArr[i][j];
						}
					}
				}
				console.log(arr)
				
			}
			radixSort(arr);

堆排序

  • 堆排序是一种不稳定的选择排序
  • 基本思想
    • 将无序序列构建为一个堆,根据升序或者降序选择大顶堆或小顶堆
    • 将堆顶元素与末尾元素交换,将最大元素放在数组末端
    • 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与末尾元素,反复执行调整和交换,直到整个序列有序
  • 图示
    在这里插入图片描述
  • 代码实现
			var arr = [4,6,8,5,9,50,-5,5];
			function heapSort(arr){
				for(let i=parseInt(arr.length/2)-1;i>=0;i--){
					adjustArr(arr,i,arr.length);
				}
				for(let i=arr.length-1;i>0;i--){
					let temp = arr[i];
					arr[i]=arr[0];
					arr[0]=temp;
					adjustArr(arr,0,i);
				}
			}
			function adjustArr(arr,i,length){
				var temp = arr[i];
				for(let k=2*i+1;k<length;k=k*2+1){
					if(k+1<length&&arr[k+1]>arr[k]){
						k++;
					}
					// if(arr[i]<arr[k]){
					if(temp<arr[k]){
						arr[i]=arr[k];
						i=k;
					}else{
						break;
					}
				}
				arr[i]=temp;
			}
			heapSort(arr);
			console.log(arr)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值