常见的排序算法

  常见的排序算法大体可以分为七中,分别为 冒泡排序,选择排序,插入排序,希尔排序,堆排序,归并排序,快速排序,

下表为各自的时间复杂度以及稳定性。

     稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

排序方法平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(n^2)O(n)O(n^2)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
插入排序O(n^2)O(n)O(n^2)O(1)稳定
希尔排序O(nlogn)~O(n^2)O(n^1.3)O(n^2)O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
快速排序O(nlogn)O(nlogn)O(n^2)O(logn)~O(n)不稳定

 

  冒泡排序:

//冒泡排序,依次递增
	// 时间复杂度: O(N ^ 2)
	// 空间复杂度: O(1)
	// 稳定性: 稳定排序
	public void BubbleSort(int[] arr){
		int tmp;
		for(int i=0;i<arr.length;i++){
			for(int j=arr.length-1;j>i;j--){
				if(arr[j]<arr[j-1]){
					tmp=arr[j];
					arr[j]=arr[j-1];
					arr[j-1]=tmp;
				}
			}
		}
		PrintArr(arr);
	}

 

选择排序:

//选择排序,依次递增
	// 时间复杂度: O(N ^ 2)
	// 空间复杂度: O(1)
	// 稳定性: 不稳定
	public void SelectSort(int []arr){
		int tmp;
		for(int i=0;i<arr.length;i++){
			for(int j=i;j<arr.length;j++){
				if(arr[j]<arr[i]){
					tmp=arr[j];
					arr[j]=arr[i];
					arr[i]=tmp;
				}
			}
		}
		PrintArr(arr);
	}

插入排序:

     

//插入排序,依次递增
	//时间复杂度: O(N ^ 2)
	//空间复杂度: O(1)
	//稳定性: 稳定排序
	public void InsertSort(int []arr){
		int bound;
		for(bound=1;bound<arr.length;bound++){
			int tmp=arr[bound];
			int i=bound;
			while(i>0&&arr[i-1]>tmp){//每次只移一个
				arr[i]=arr[i-1];
				i--;
			}
			arr[i]=tmp;
		}
		PrintArr(arr);
	}	

 

堆排序:

 

// 堆排序,依次递增
	// 时间复杂度: O(NlogN)
	// 空间复杂度: O(1)
	// 稳定性: 不稳定排序
	//向下调整,建大堆
	public static void AdjustDown(int []arr,int size,int parent){
		int child=parent*2+1;
		while(child<size){
			if(child+1<size&&arr[child]<arr[child+1])
			{
				child=child+1;
			}
			if(arr[child]>arr[parent]){
				int tmp;
			tmp=arr[parent];
			arr[parent]=arr[child];
			arr[child]=tmp;
			}

			else{
				break;
			}
			parent=child;
			child=parent*2+1;
		}
	}
	//建堆
	public  static void HeapMake(int []arr,int size){
		if (size <= 1) {
			return;
		}
		for(int i=(size-2)/2;i>=0;i--){
			AdjustDown(arr, size,i);
		}
	}
	//删除堆顶元素
	public static void Pop(int []arr,int size){
		if(size<=1){
			return ;
		}
		int tmp;
		tmp=arr[size-1];
		arr[size-1]=arr[0];
		arr[0]=tmp;
		AdjustDown(arr,size-1, 0);
	}
	public void HeapSort(int []arr){
		HeapMake(arr, arr.length);

		for(int i=0;i<arr.length;i++){
			Pop(arr, arr.length-i);
		}
		PrintArr(arr);
	}

希尔排序:

  

// 希尔(Shell)排序,,依次递增, 一种改进版本的插入排序
	// 时间复杂度: 对于希尔序列, O(N ^ 2);
	// 对于最优序列, 复杂度达到 O(N ^ 1.3)
	// 空间复杂度: O(1)
	// 稳定性: 不稳定排序
	public void ShellSort(int []arr)
	{
		int length=arr.length;
		int gap=length/2;
		for(;gap>0;gap/=2)//分组
		{
			int bound=gap;//希尔排序的要点,1.分组
						  //2.采用插入排序(注意每一个元素的下标)
			for(;bound<arr.length;bound++){
				//直接从每组的第二个元素开始插入
				int tmp=arr[bound];
				int i=bound;
				while(i>=gap&&arr[i-gap]>tmp){
					arr[i]=arr[i-gap];//循环搬移
					i=i-gap;
				}
				arr[i]=tmp;
			}
		}
		PrintArr(arr);
	}

 

递归版归并排序:

  

// 归并排序,依次递增
	// 时间复杂度: O(NlogN)
	// 空间复杂度: 对于数组来说, O(N)
	// 稳定性: 稳定排序
	public void MergeSort(int []arr){		
		int length=arr.length;
		int []tmp=new int[length];
		_MergeSort(arr,0,length-1,tmp);
		PrintArr(arr);
	}

	private static void _MergeSort(int[] arr, int beg, int end, int[] tmp) {
		if(end-beg<1){
			return ;
		}
		//分成一个个数组
		int mid=beg+(end-beg)/2;
		_MergeSort(arr,beg,mid,tmp);//左边归并排序,使左边有序
		_MergeSort(arr,mid+1,end,tmp);//右边归并排序,使右边有序
		MergeArray(arr,beg,mid,end,tmp);//合并
	}
	//将数组有序合并
	private static void MergeArray(int[] arr, int beg, int mid, int end,
			int[] tmp) {
		int output_index=0;//临时数组指针
		int  cur1=beg;//左序列指针
		int cur2=mid+1;//右序列指针
		while (cur1<=mid && cur2<=end) {
			if(arr[cur1]<arr[cur2]){
				tmp[output_index++]=arr[cur1++];
			}
			else{
				tmp[output_index++]=arr[cur2++];
			}
		}
		while(cur1<=mid){
			tmp[output_index++]=arr[cur1++];
		}
		while(cur2<=end){
			tmp[output_index++]=arr[cur2++];
		}
		output_index=0;
		while(beg<=end){
			arr[beg++]=tmp[output_index++];
		}
	}

 

非递归归并排序:

	//非递归归并排序
	public void MergeSortByLoop(int []arr) {
		int length=arr.length;
		int []tmp=new int [length];
		int gmp=1;//当前的步数
		for(;gmp<arr.length;gmp=gmp*2) {
			for(int i=0;i+gmp<arr.length;i=i+gmp*2) {
				//循环处理相邻的两个区间
				int beg=i;
				int mid=i+gmp-1;
				if(mid>arr.length-1) {
					mid=arr.length-1;
				}
				int end=i+2*gmp-1;
				if(end>arr.length-1) {
					end=arr.length-1;
				}
				MergeArray(arr, beg, mid, end, tmp);
			}
		}
		PrintArr(arr);	
	}

 

递归快速排序:

// 快速排序,依次递增
	// 时间复杂度: 最坏 O(N ^ 2)(如果数组是逆序的) 平均水平 O(NlogN)
	// 空间复杂度: O(N) 递归. 最坏情况下要递归 N 层
	// 稳定性: 不稳定排序
	public static int Partion(int[]arr,int beg,int end) {
		int key=arr[end];
		int left=beg;
		int right=end;
		while(left<right) {
			//找到比基准值大的数字,左指针加一
			while(left<right&&arr[left]<=key) {
				left++;
			}
			//找到比基准值小的数字,右指针减一
			while(left<right&&arr[right]>=key) {
				right--;
			}
			//左边比基准值大,右边比基准值小。
			int tmp=arr[left];
			arr[left]=arr[right];
			arr[right]=tmp;
		}
		//将基准值放在应该在的位置
		int tmp=arr[left];
		arr[left]=arr[end];
		arr[end]=tmp;	
		
		return left;		
	}
	public static void _QuickSort(int[]arr,int left,int right) {
		if(left>=right) {
			return ;
		}
		int mid=Partion(arr, left, right);
		_QuickSort(arr, left, mid-1);
		_QuickSort(arr, mid, right);
	}
	public void QuickSort(int[]arr) {
		int right=arr.length-1;
		_QuickSort(arr,0,right);
		PrintArr(arr);
	}

 

非递归快速排序:

 

//非递归快速排序,借助栈
	//操作思路和归并排序很像, 都是倒腾区间
	public void QuickSortByloop(int []arr) {
		int length=arr.length;
		int beg=0;
		int end=length-1;
		Stack<Integer>stack=new Stack<Integer>();
		stack.push(beg);
		stack.push(end);
		while(!stack.empty()) {
			int right=stack.pop();
			int left=stack.pop();
			  if(left<right) {
				int mid=Partion(arr, left, right);
				// 此时又得到了两个待整理区间:
				// [beg, mid)
				// [mid+1, end)
				if((mid-1)>left) {    //左边待排序区间
					stack.push(beg);  
				stack.push(mid);
				}
				if((mid+1)<right) {  //右边已经排序好的区间
				stack.push(mid+1);
				stack.push(end);
				}
			}
		}
		PrintArr(arr);
	}
	

 

以上为七种排序算法的代码,代码为个人所思所写,若有错误,欢迎随时指教,不胜感激。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值