基础算法-排序(插入&希尔&归并)

基础算法-排序(插入&希尔&归并)

基本概念

排序算法有哪些

快速排序、冒泡排序、希尔排序、二分(归并)排序O(nlogn)、桶排序、堆排序、基数排序、插入排序O(n^2)、选择排序

插入&希尔&归并

冒泡&选择&快速

堆排序:树论高级篇

分析排序算法的几个方面:

1.时间复杂度
2.空间复杂度
3.比较次数&交换次数:排序肯定有比较和交换两个操作,
4.稳定性:(相同的两个元素,排序后相对位置不变)
1 9 3(1) 5 3(2)
1 3(1) 3(2) 5 9排序后是这样而不是1 3(2) 3(1) 5 9

稳定排序有什么意义?应用在哪里?

电商里面订单排序:首先按金额大小从小到大排序,金额相同的按下单时间。从订单中心过来时已经按照时间排好序,要求进行金额排序:
1 8:01 65
2 20:05 30
3 21:10 30
4 22:01 45
选择排序算法:如果选择不稳定的排序算法,就要比较两次,如果选择稳定的排序算法,那就只要比较一个字段。

插入排序(稳定的)

类似于打扑克
一个有序的数组,往里面添加一个新的数据后,如何继续保持数据的有序呢?找到数据应该插入的数据将其插入即可。(把一个无序的数列一个个插入到有序的数列中)

实现步骤:

1.将数组分成已经排序段和未排序段。初始化时排序段只有一个元素
2.到未排序段去元素插入到已排序段,并保证插入后仍然有序
3.重复执行以上操作,直到未排序段元素全部加完

代码实现
package Sort;

public class InsertSort {
	/* 
	 * 插入排序
	 * 1.将数组分成已经排序段和未排序段。初始化时排序段只有一个元素
	 * 2.到未排序段去元素插入到已排序段,并保证插入后仍然有序
	 * 3.重复执行以上操作,直到未排序段元素全部加完
	 */

	public static void main(String[] args) {
		int a[]={9,8,7,0,1,3,2};
		int n=a.length;
		//这有两层循环
		//时间复杂度O(n^2)
		//最好时间复杂度O(n);
		for (int i=1;i<n;i++){//为什么从i开始,第一个不用排序,我们从i分开,0~i的认为已经排好序
			int data =a[i];
			int j;
			for(j=i-1;j>=0;j--){        //从尾到头在排好序的部分进行遍历,从后往前遍历 找到插入的数据时,需要往后移位置(数组元素移位)因此不用从头到尾
				if(a[j]>data){
					a[j+1]=a[j];    //往后移动
				}else{  //前面是排好序的,找到一个比data小的不用再找
					break;//break执行的越多,程序的效率就越高
				}
			}
			a[j+1]=data;
			System.out.print("第"+i+"次的排序结果为:");
			for(j=0;j<n;j++){
				System.out.print(a[j]+" ");
			}
			System.out.println();
		}
		
	}
}
运行结果:
第1次的排序结果为:8 9 7 0 1 3 22次的排序结果为:7 8 9 0 1 3 23次的排序结果为:0 7 8 9 1 3 24次的排序结果为:0 1 7 8 9 3 25次的排序结果为:0 1 3 7 8 9 26次的排序结果为:0 1 2 3 7 8 9 

希尔排序(对插入排序的优化)(不稳定的)

具体过程:
按照一个增量分段:add=n/2 n=10=>5=>2=>1
7 8 9 0 4 3 1 2 5 10
7和3一组,8和1一组·········
3 8 9 0 4 7 1 2 5 10以此类推完成第一次排序
结果:3 1 2 0 4 7 8 9 5 10
3 2 4 8 5一组(增量为2的分为一组)剩下1 0 7 9 10一组
最后去增量为1的一组
希尔排序的优化原理就是使得增量为1时数列中有序得到数更过,增加插入排序代码中第24行break的执行次数达到优化效果

归并排序(稳定的)

具体过程演示

有n个元素需要分logn次
9 5 6 8 0 3 7 1
9 5 6 8 · 0 3 7 1
9 5 · 6 8 · 0 3 · 7 1
以上为分的过程
以下为并的过程
5 9 · 6 8 · 0 3 · 1 7
5 6 8 9 · 0 1 3 7
0 1 3 5 6 7 8 9

分析:

时间复杂度:O(nlogn)
其他的和插入排序一样

代码实现
package Sort;

import java.util.Arrays;

public class MergeSort {
	private static int temp[];
	public static void main(String[] args) {
		int data []={10,9,5,6,8,0,3,7,1};
		temp = new int [data.length];
		mergeSort(data, 0, data.length-1);
		System.out.println(Arrays.toString (data));//Arrays.toString (data)直接打印数组
	}
	
	public static void  mergeSort(int data[],int left,int right) {   //left和right是数组的两端
		if (left<right){    //相等之后就表示只有一个数了,不再拆了
			int mid =(left+right)/2;
			mergeSort(data, left, mid);
			mergeSort(data, mid+1, right);
			//分完了,接下来进行合并
			merge(data, left, mid, right);
		}
	}
	public static void merge(int data[],int left,int mid, int right){
		//int temp[]=new int [data.length];    不在此处开辟数组是为了防止数据量过大时,每次开辟内存时间过长
		int point1 = left;           //表示左边第一个数的位置
		int point2 = mid+1;          //表示右边第一个数的位置
		int local = left;            //表示当前已经到的哪个位置,因为最开始从左边开始
		while (point1 <= mid && point2 <= right){
			if (data[point1]<data[point2]){
				temp[local]=data[point1]; 
				point1++;
				local++;
			}else{
				temp[local]=data [point2];
				point2++;
				local++;
			}
		}
		while (point1 <=mid){
			temp[local++]=data[point1++];
		}
		while (point2<=right){
			temp[local++]=data[point2++];
		}
		for (int i=left;i<=right;i++){
			data[i]=temp[i];
		}
	}

}

图解

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值