0
点赞
收藏
分享

微信扫一扫

数据结构与算法(九)——冒泡排序、选择排序、插入排序

_刘彦辉 2022-04-15 阅读 58
数据结构

冒泡排序

基本思想

通过对待排序的序列从前往后,依次比较相邻的两个元素的值,如果发现逆序则交换,使的最大(降序则最小)的元素逐渐从前移到后部,像水底的气泡逐渐向上冒;每一轮排序结束,就保证了当前无序的序列中的最大的元素已经到了序列尾部

代码实现

/**
 * 冒泡排序
 * @author laowa
 *
 */
public class BubbleSort {
	public static void main(String args[]) {
		int arr[]= {3,9,-1,10,-2};
		bubbleSort(arr);
		System.out.println("最终排序结果为");
		print(arr);
	}
	
	/**
	 * 冒泡排序
	 * @param arr 待排序的数组
	 */
	private static void bubbleSort(int[] arr) {
		//使用一个标志量来优化算法,当某趟冒泡结束后,没有发生数字的交换,说明当前任意两个相邻的数都是有序的,则该数组已有序
		boolean isSorted = true;
		//临时变量用户交换前后变量
		int temp;
		for(int i=0;i<arr.length-1;i++) {
			for(int j=0;j<arr.length-1-i;j++) {
				if(arr[j]>arr[j+1]) {
					//当前后数据逆序,则进行交换
					//标志量改为false,表示当前趟的冒泡发生了交换
					isSorted=false;
					temp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}
			}
			//如果标志量没有被改变,即序列已有序,直接返回
			if(isSorted) {
				return;
			}
			isSorted=true;
			System.out.printf("第%d轮排序的结果为\n",i+1);
			print(arr);
		}
	}
	
	/**
	 * 打印数组
	 * @param arr 待打印的数组
	 */
	private static void print(int []arr) {
		for(int i:arr) {
			System.out.print(i+" ");
		}
		System.out.println();
	}
}

速度测试

在这里插入图片描述
代码中使用了循环嵌套,冒泡的时间复杂度为O(n2),在十万级的数据量下,冒泡排序耗时高达16秒

选择排序

基本思想

选择排序也属于内部排序,它的基本思想是:在arr[n]数组中,第一次从arr[0]~arr[n-1]中选取最小值,与arr[0]交换第二次从arr[1]~arr[n-1]中选取最小值,与arr[1]交换。。。进行n-1次,得到一个有序序列

代码实现

/***
 * 选择排序
 * @author laowa
 *
 */
public class SelectSort {

	public static void main(String[] args) {
		int arr[]= {101,34,119,1};
		selectSort(arr);
		System.out.println("最终排序结果为");
		print(arr);
		timeTest();

	}
	
	/**
	 * 排序时间检查
	 */
	private static void timeTest() {
		int count = 100000;
		int arr[] = new int[count];
		for(int i=0;i<count;i++) {
			arr[i]=new Random().nextInt(count);
		}
		long before = System.currentTimeMillis();
		selectSort(arr);
		long after = System.currentTimeMillis();
		System.out.printf("排序%d个数用时%d毫秒", count,after-before);
	}

	/**
	 * 选择排序
	 * @param arr 待排数组
	 */
	private static void selectSort(int[] arr) {
		//存储当前轮找到的最小值
		int min;
		//当前轮找到的最小值的索引
		int minIndex;
		for(int i=0;i<arr.length-1;i++) {
			//初始化最小值为当前轮的第一个元素
			min = arr[i];
			minIndex = i;
			//从i+1开始,因为第i个已经取得了,依次找最小值
			for(int j=i+1;j<arr.length;j++) {
				//依次将无序列中的数与最小值比较,取最小值
				if(min>arr[j]) {
					min = arr[j];
					minIndex = j;
				}
			}
			//将最小值和当前轮的1个元素交换
			arr[minIndex]=arr[i];
			arr[i]=min;
		}
	}
	
	/**
	 * 打印数组
	 * @param arr 待打印的数组
	 */
	private static void print(int []arr) {
		for(int i:arr) {
			System.out.print(i+" ");
		}
		System.out.println();
	}
}

速度测试

在这里插入图片描述
代码使用了循环嵌套,时间复杂度为O(n2),但是选择排序每一轮排序只进行一次交换,省去了大量的交换时间,所以比冒泡排序用户要低很多,在十万级的数据下耗时约两秒

插入排序

基本思想

把n个待排序的元素看成一个有序表和一个无序表,开始时有序表只包含一个元素,无序表包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码一次与有序表中元素的排序码进行比较,将他插入到有序表中的适当位置,使之成为新的有序表

代码实现

/***
 * 插入排序
 * @author laowa
 *
 */
public class InsertSort {

	public static void main(String[] args) {
		int []arr= {101,34,119,1,-1,89};
		insertSort(arr);
		System.out.println("插入排序之后的结果为");
		print(arr);

	}
	
	/**
	 * 插入排序
	 * @param arr 待排数组
	 */
	private static void insertSort(int []arr) {
		//当前需要插入的值
		int insertVal;
		//表示插值的位置
		int insertIndex;
		//最初以第一个元素作为有序序列,所以从i=1开始遍历
		for(int i=1;i<arr.length;i++) {
			//当前遍历到的值即需要插入的值
			insertVal=arr[i];
			//从当前值的前一个位置开始,往前遍历
			insertIndex=i-1;
			
			//for循环形式
			//从i-1,即有序序列的最后一个元素开始往前遍历
			for(insertIndex=i-1;insertIndex>=0;insertIndex--) {
				//如果遍历到的元素比待插的值大,说明要插在这个元素前面,将这个元素向后移动
				if(arr[insertIndex]>insertVal) {
					arr[insertIndex+1]=arr[insertIndex];
				}else {
					//否则表示这个值要插的位置已经找到了,跳出循环,将待插值插在这个值的后面
					break;
				}
			}
			arr[insertIndex+1]=insertVal;
			
			//while循环形式
			//一直往前查找,直到找到第一个位置或者需要插入的值大于某个位置的值
			while(insertIndex>=0&&insertVal<arr[insertIndex]) {
				//将当前位置的值往后移动
				arr[insertIndex+1]=arr[insertIndex];
				//位置向前移动
				insertIndex--;
			}
			//当while循环结束后,表示都找到了当前值需要插入的位置
			//要么当前的insertIndex=-1跳出,那么将值插在0位置上
			//要么当前arr[inserIndex]<=insertVal那么将这个值插在arr[insertIndex]的后面
			arr[insertIndex+1]=insertVal;
		}
	}
	
	/**
	 * 打印数组
	 * @param arr 待打印的数组
	 */
	private static void print(int []arr) {
		for(int i:arr) {
			System.out.print(i+" ");
		}
		System.out.println();
	}

}

速度测试

在这里插入图片描述
插入排序也是双重循环,时间复杂度为O(n2),因为每次内层循环都会有多次赋值操作,相对于冒泡的交换要少,但相对于选择的一个循环一次要多,十万级的数量用户约四秒

举报

相关推荐

0 条评论