三大基本排序总结 (冒泡、选择、插入)

1.冒泡排序

(1)方法描述:

冒泡排序(bubble sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

(2)算法原理:

1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

3.针对所有的元素重复以上的步骤,除了最后一个。

4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

(3)算法评价

时间复杂度:最好的情况(全部正序)---比较次数n-1

---移动次数0

                     最坏的情况(全部正序)---比较次数1/2 ( n*n - n )

---移动次数3/2 ( n*n - n )

空间复杂度:S(n)=O(1)

代码实现:

下列三种排序的公共代码:

public void swap(int a[],int i,int j){
		int temp=a[i];
		a[i]=a[j];
		a[j]=temp;
	}
	
	public void print(int[] a){
		for(int x:a){
			System.out.print(x+" ");
		}
		System.out.println();
	}

冒泡排序代码实现:

1.普通冒泡排序

@Test
	public void bubbleSort(){
		int a[]={1,0,-1,13,4,7,13,49};
		print(a);
		
		for(int i=0;i<a.length-1;i++){//当只剩最后一个元素时,不需要在冒泡
			for(int j=0;j<a.length-i-1;j++){
				//j:0~n-i+1
				if(a[j]>a[j+1]){
					swap(a, j, j+1);
				}
			}
		}
		
		print(a);
	}
2:优化后冒泡排序

@Test
	public void bubbleSort_2(){
		int a[]={1,0,-1,13,4,7,13,49};
		print(a);
		for(int i=0;i<a.length-1;i++){//当只剩最后一个元素时,不需要在冒泡
			boolean boo=true;
			for(int j=0;j<a.length-i-1;j++){
				//j:0~n-i+1
				if(a[j]>a[j+1]){
					boo=false;
					swap(a, j, j+1);
				}
			}
			if(boo){
				//如果进行一趟比较之后,没有交换位置,说明每一个位置都满足a[j]<a[j+1],则整个序列有序
				break;
			}
		}
		print(a);
	}

2: 选择排序
(1)方法描述

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

(2)算法原理

1:通过n-1次比较,从n个数中找出最小的, 将它与第一个数交换——第一趟选择排序,结果最小的数被安置在第一个元素位置上。
2:通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换——第二趟选择排序。
3:重复上述过程,共经过n-1趟排序后,排序结束。

(3)算法评价

时间复杂度: 最好的情况(全部正序)---比较次数1/2 (- n )

---移动次数0

                     最坏的情况(全部正序)---比较次数1/2 ( - n )

---移动次数3 ( n - 1 )

空间复杂度:S(n)=O(1)

相对于冒泡算法,选择排序更优


代码实现:

@Test
	public void selectSort_2(){
		int a[]={1,0,-1,13,4,7,13,49};
		print(a);
		
		for(int i=0;i<a.length-1;i++){
			int k=i;
			for(int j=i+1;j<a.length;j++){
				//从i+1位置开始往后查找,如果有比当前位置的数小的数,则记录那个小数的位置
				if(a[k]>a[j]){
					k=j;
				}
			}
			//进行一趟查找后,k记录的是最小数的下标
			if(k!=i){
				swap(a, i, k);
			}
		}
		print(a);
	}


3: 插入排序

插入排序:1:直插入排序

  2:二分插入排序(在直接插入排序的基础上,利用二分(折半)查找算法决策出当前元素所要插入的位置。)

(1)方法描述

插入排序(insert sort)就是每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

(2)算法原理

记录存放在数组R[0….n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0…i-1]和R[i….n-1],其中:前一个子区间是已排好序的有序区;后一个子区间则是当前未排序的部分。    将当前无序区的第1个记录R[i]插入到有序区R[0….i-1]中适当的位置,使R[0…i]变为新的有序区。

(3)算法分析

插入排序是一个稳定的排序方法。

最好情况下, 排序前记录已按关键字从小到大有序, 每趟只需与前面有序记录序列的最后一个记录比较1次, 移动2次记录, 

总的关键字比较次数为 n-1, 记录移动次数为 2(n-1)。

在平均情况下的关键字比较次数和记录移动次数约为n² /4。

空间复杂度:S(n)=O(1)
(4)二分查找

二分查找:找到中间元素,如果中间元素比当前元素大,则当前元素要插入到中间元素的左侧;否则,中间元素比当前元素小,则当前元素要插入到中间元素的右侧。

代码实现:

	@Test
	public void insertSort(){
		int a[]={1,0,-1,13,4,7,13,49,31,21,3};
		print(a);
		
		//依次把每个数插入到有序序列中
		for(int i=0;i<a.length-1;i++){		//i+1表示待插入的数的下标  所以循环执行到a.length-1
			//temp表示待插入数
			int temp=a[i+1];
			//j表示前j个数有序
			int j=i;
			/*
			 * 下面一段代码表示:从最后一个有序位置往前查找,
			 * 若待插入数,比位置j的数小,则把位置j的数往后挪
			 * 直到j<0超出了左边界,或者待插入数比位置j的数大,则把待插入数放在j+1位置
			 */
			while(temp<a[j]){
				a[j+1]=a[j];
				j--;
				if(j<0){
					break;
				}
			}
			a[j+1]=temp;
		}
		print(a);
	}

	//带二分的插入排序
	//★二分必须有序,如果有序可以考虑二分
	
	@Test
	public void insertSort_2(){
		int a[]={1,0,-1,13,4,7,13,49,31,21,3};
		print(a);
		
		//(0,i)区间的数是有序的
		for(int i=0;i<a.length-1;i++){
			//待插入数
			int temp=a[i+1];
			//二分法查找,插入位置,high+1
			int low=0;
			int high=i;
//			int mid=(low+high)/2;  这样做mid一直没变,会错
			int mid;
			
			while(low<=high){
				mid=(low+high)/2;
				//只有当high到low的左边时,此时待插入数的位置为high+1
				if(temp>a[mid]){
					//待插入数比中间位置的数大,则位于右区间
					//因为待插入数比mid位置的数大,所以可以使下一次的最低位为mid+1
					low=mid+1;
				}else{
					//待插入数比中间位置的数小,则位于左区间
					//因为待插入数比mid位置的数小或者等于,所以可以使下一次的最高位为mid-1
					high=mid-1;
				}
			}
			//循环结束后high将位于low的左边,high+1即为待插入数的位置
			//把high+1后面的数全部往后挪一位,空出位置给待插入数
			//此处应该注意,要从有序的最后一位(i位置)开始挪,不然值会覆盖,
			for(int j=i;j>high;j--){
				a[j+1]=a[j];
			}
			//把待插入数放在腾出来的high+1位置
			a[high+1]=temp;
		}
		
		print(a);
	}




插入排序是一个稳定的排序方法。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值