冒泡排序和选择排序

冒泡排序

package 排序算法;

import java.util.Arrays;

import org.junit.Test;
/*
* 冒泡排序:
*从 arr[0]起,前一个依次和后一个比,谁大谁放后面,直到最后一个元素,确定最大的
*从 arr[0]起,前一个依次和后一个比,谁大谁放后面,直到次后个元素,确定第二二的
*从 arr[0]起,前一个依次和后一个比,谁大谁放后面,直到次次后个元素,确定第三大的
*..........
* .........
*/
public class BubblingSort {
	/*
	 * 冒泡排序算法
	 */
	@Test
	public void sort() {
		//生成长度20的随机数组
		int [] arr=new int[20];
		for(int i=0;i<arr.length;i++) {
			arr[i]=(int)(Math.random()*100+1); 
		}
		//记录交换次数
		int count=0;
		//外层for循环
		for (int i=0;i<arr.length;i++) {
			//前后两数比较,满足条件则交换
			for (int j=1;j<arr.length-i;j++) {
				if(arr[j-1]>arr[j]) {
					arr[j]=arr[j-1]+arr[j];
					arr[j-1]=arr[j]-arr[j-1];
					arr[j]=arr[j]-arr[j-1];
					count++;
				}				
			}
		}
		System.out.println("排序后的数组:"+Arrays.toString(arr)+"\n 排序次数:"+count);		
	}		
}

运行结果

排序后的数组:[7, 8, 11, 14, 16, 17, 19, 20, 25, 30, 50, 52, 55, 61, 64, 66, 68, 93, 98, 100]
 排序次数:73

优化后的冒泡排序 

package 排序算法;

import java.util.Arrays;
import org.junit.Test;

public class OptimizeBubblingSort {
	/*
	 * 冒泡排序算法
	 */
	@Test
	public void sort() {
		//生成长度20的随机数组
		int [] arr=new int[20];
		for(int i=0;i<arr.length;i++) {
			arr[i]=(int)(Math.random()*100+1); 
		}
		//记录交换次数
		int count=0;
		//外层for循环
		for (int i=0;i<arr.length;i++) {
			//记录下最大数的下标,默认当前序列尾部元素最大
			int index=arr.length-1-i;
			//查找当前序列真实的最大的数下标
			for (int j=1;j<arr.length-i;j++) {
				if(arr[j-1]>arr[index]) {
					index=j-1;					
				}				
			}
			//如果不是尾部元素最大,则交换并记录交换次数
			if(index!=arr.length-1-i) {
				arr[arr.length-1-i]=arr[index]+arr[arr.length-1-i];
				arr[index]=arr[arr.length-1-i]-arr[index];
				arr[arr.length-1-i]=arr[arr.length-1-i]-arr[index];
				count++;
			}
		}
		System.out.println("排序后的数组:"+Arrays.toString(arr)+"\n 排序次数:"+count);		
	}		
}

运行结果

排序后的数组:[12, 16, 18, 30, 32, 35, 43, 46, 50, 53, 56, 56, 58, 67, 67, 75, 93, 94, 94, 98]
 排序次数:15

实质上优化过后的冒泡排序就是选择排序了。

选择排序 

package 排序算法;

import java.util.Arrays;

import org.junit.Test;
/* 
* 选择排序:
* arr[0]依次和arr[1]...arr[arr.length-1]比较,记录下最小的数,与arr[0]交换位置
* arr[1]依次和arr[2]...arr[arr.length-1]比较,记录下最小的数,与arr[1]交换位置
* arr[2]依次和arr[3]...arr[arr.length-1]比较,记录下最小的数,与arr[2]交换位置
* .........
* 
* .........
*/
public class SelectionSort {
	/*
	 * 选择排序算法
	 */
	@Test
	public  void sort() {
		//生成一个长度为20的随机数组
		int [] arr=new int[20];
		for(int i=0;i<arr.length;i++) {
			arr[i]=(int)(Math.random()*100+1);
		}
		//记录交换次数
		int count=0;
		//外层循环
		for(int i=0;i<arr.length;i++) {
			//记录最小的元素下标,默认头部元素最小
			int index=i;
			//查找当前序列中最小的元素下标
			for(int j=i+1;j<arr.length;j++) {
				if(arr[j]<arr[index]) {
					index=j;
				}
			}
			//如果不是头部元素最小,则交换并记录交换次数
			if(index!=i) {
				arr[index]=arr[index]+arr[i];
				arr[i]=arr[index]-arr[i];
				arr[index]=arr[index]-arr[i];
				count++;
			}
			
		}
		System.out.println("排序后的数组:"+Arrays.toString(arr)+"\n 排序次数:"+count);		
	}
	
}

运行结果 

排序后的数组:[3, 16, 16, 17, 27, 27, 28, 30, 36, 37, 43, 43, 46, 47, 49, 56, 60, 73, 89, 92]
 排序次数:17

对比总结

1、冒泡排序是相邻两个数比,这两个比较的数一致在向右移动,选择排序是固定一个位置的数和其后的数比,只
有一个数在移动。优化过后的冒泡排序实际上就是选择排序。

2、对于数组从小到大排序
        冒泡排序第X趟下来确定第X大的元素,放在数组的倒数第X个位置
        选择排序第X趟下来确定第X小的元素,放在数组的顺数第X个位置

        冒泡排序一趟会交换很多次,是稳定的。
        选择排序一趟只交换一次,是不稳定的。
        稳定和不稳定:
            比如对于数组5,6,2,8,1 
            原本5,6顺序符合要求,但选择排序第一趟下来,2和5交换位置,5,6的从小到大顺序比打乱这就是不稳定。
            而对于选择排序,则不会出现打乱已有的满足条件的顺序,是稳定的。
            稳不稳定其实取决于一趟交换几次,交换一次肯定不稳定,优化过后的冒泡排序交换一次,不稳定。

 

冒泡排序选择排序都是基础的比较排序算法,它们在实现机制、效率以及应用场景上有显著的区别。 ### 冒泡排序选择排序的核心区别 #### 1. 工作原理 - **冒泡排序**通过重复遍历数组,比较相邻元素,并交换顺序错误的元素对,使得每一轮遍历后最大的未排序元素“冒泡”到数组末尾。这种逐次比较交换的方式决定了其名称[^1]。 - **选择排序**则采用完全不同的策略:它每次从剩余未排序部分中找到最小(或最大)的元素,然后将其放置在当前未排序段的起始位置(即已排序段的末尾)。这种方式避免了频繁的元素交换操作[^2]。 #### 2. 时间复杂度 - **冒泡排序**的最坏平均时间复杂度均为 $ O(n^2) $,其中 $ n $ 是待排序数组的长度。即使在最佳情况下(数组已经有序),如果未进行优化,则仍需 $ O(n^2) $ 的时间;但若加入提前终止机制,最佳情况可优化为 $ O(n) $[^1]。 - **选择排序**的时间复杂度始终为 $ O(n^2) $,无论输入数据是否已经部分有序。由于其选择最小元素并仅一次交换的特点,它不会因数据有序性而减少比较次数[^2]。 #### 3. 空间复杂度 - 两者均是原地排序算法,空间复杂度为 $ O(1) $,因为它们不需要额外的存储空间。 #### 4. 稳定性 - **冒泡排序**是稳定排序算法,因为它只在相邻元素不满足顺序时才进行交换,从而保证了相等元素的相对顺序不变[^1]。 - **选择排序**则是不稳定的排序方法,因为在寻找最小元素的过程中可能会将不同位置的相等元素调换顺序[^2]。 #### 5. 实现代码对比 以下是两种排序算法的 JavaScript 实现示例: ```javascript // 冒泡排序 Array.prototype.bubble_sort = function() { var i, j, temp; for (i = 0; i < this.length - 1; i++) for (j = 0; j < this.length - 1 - i; j++) if (this[j] > this[j + 1]) { temp = this[j]; this[j] = this[j + 1]; this[j + 1] = temp; } return this; } ``` ```javascript // 选择排序 Array.prototype.selection_sort = function() { var i, j, minIndex, temp; for (i = 0; i < this.length - 1; i++) { minIndex = i; for (j = i + 1; j < this.length; j++) if (this[j] < this[minIndex]) minIndex = j; if (minIndex !== i) { temp = this[i]; this[i] = this[minIndex]; this[minIndex] = temp; } } return this; } ``` #### 6. 应用场景 - **冒泡排序**虽然效率不高,但由于其实现简单且具有稳定性,适合教学用途或小规模数据集。 - **选择排序**虽然同样效率较低,但其简单性最少的交换次数使其适用于内存写入成本较高的场合,例如嵌入式系统或硬件限制环境。 ### 总结 冒泡排序选择排序的主要区别在于: - 冒泡排序通过相邻元素的多次交换来逐步构建有序序列,而选择排序通过单次交换最小元素至正确位置; - 冒泡排序是稳定的,而选择排序是不稳定的; - 在某些特定场景下,选择排序可能比冒泡排序更高效,尤其是当交换代价较高时。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二百四十九先森

你的打赏是我努力的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值