【数据结构与算法09】排序算法

public class Sort {

	
	/**
	 * 名称:冒泡排序
	 * 顺序:从小到大(非必须)
	 * 逻辑:循环比较数组中相邻的数,较大的数放在下标较大的位置。比较的时候就会发生移动
	 * 原则:找到最大的数,放到最右边
	 * 例子:假如数组为{3,2,1}
	 * 先把3和2比较,换位置{2,3,1},再3和1比较,换位置{2,1,3}
	 * 再2和1比较,换位置{1,2,3}
	 */
	public static void bubbleSort(int[] a) {
		boolean isContinue;
		int num = 0;
		for (int i = 0; i < a.length; i++) {
			isContinue = false;
			for (int j = 0; j < a.length - 1 - i; j++) {
				if (a[j] > a[j + 1]) {
					num = a[j];
					a[j] = a[j + 1];
					a[j + 1] = num;
					isContinue = true;
				}
			}
			// 如果没有发生位置变化,不需要再继续比了。
			if (!isContinue)
				break;
		}
	}
	
	/**
	 * 名称:选择排序
	 * 顺序:从左到右,小到大(非必须)
	 * 逻辑:循环从左到右依次比较找到最小的数,跟循环次数N-1的下标位置的数互换。一次完整的比较移动一次
	 * 原则:找到最小的数,放到最左边
	 * 例子:假如数组为{3,2,1}
	 * 先把3和2比较,找到2,再2和1比较,找到1,然后1,3换位置{1,2,3}
	 * 再2和3比较,结束
	 */
	public static void selectSort(int[] a) {
		int min;
		for (int i = 0; i < a.length; i++) {
			min = i;
			for (int j = i + 1; j < a.length; j++) {
				if (a[j] < a[min])
					min = j;
			}
			int num = a[i];
			a[i] = a[min] ;
			a[min] = num ;
		}
	}

	/**
	 * 名称:插入排序
	 * 顺序:从左到右,小到大
	 * 逻辑:从第二个开始,依次与左边的比较,遇到比自己大的时位置互换。
	 * 原则:在这个数的左边找到自己的位置
	 * 例子:假如数组为{3,2,1}
	 * 基数2,先把2和3比较,换位置{2,3,1}
	 * 再基数1,先1和3比较,换位置{2,1,3},再1和2比较,换位置{1,2,3}
	 */
	public static void insertSort(int[] a) {
	    for(int i = 1; i < a.length; i++) {
	        for(int j = i; j > 0; j--) {
	        	if(a[j] < a[j-1]){
	        		int num = a[j];
					a[j] = a[j-1] ;
					a[j-1] = num ;
	        	}
	        }
	    }
	}
	
	/**
	 * 名称:归并排序
	 * 顺序:从左到右,小到大
	 * 逻辑:把一个数组分成两半,再分成两半,一直分,直到每一半只有1个元素,
	 * 然后把分出来的两个只有1个元素的数组排序合并成一个数组,
	 * 然后继续排序合并直到完成整个排序。
	 * 注意这里是把下标分段。
	 * 原则:分段比较
	 * 例子:假如数组为{8,4,2,7,9,10}
	 * 		先分成{8,4,2}{7,9,10}
	 * 		在分成{8,4}{2}{7,9}{10}
	 * 		在分成{8}{4}{2}{7}{9}{10}
	 * {8}{4}是一个分出来的,先比较{8}{4},成为{4,8}
	 * 在与{2}比较,成为{2,4,8}。右边成为{7,9,10},
	 * 在比较{2,4,8}{7,9,10},
	 * 拿这个当例子说一下比较过程,上面也是一样的
	 * 2跟7比,把小2复制到临时数组backup{2}
	 * 然后4跟7比,把小4复制到backup{2,4}
	 * 然后8跟7比,把小7复制到backup{2,4,7}
	 * 然后8跟9比,把小8复制到backup{2,4,7,8}
	 * 然后发现左边的比完了,没数据了,那就把右边的全都直接复制到backup
	 * 成为{2,4,7,8,9,10}
	 */
	public static void mergeSort(int[] a){
		int[] backup = new int[a.length];
		recMergeSort(backup, 0, a.length-1, a);
	}
	
	private static void recMergeSort(int[] backup ,int startIndex,int endIndex,int[] a){
		if(startIndex == endIndex){
			return ;
		}else{
			int mid = (startIndex + endIndex)/2 ;
			recMergeSort(backup, startIndex, mid, a);
			recMergeSort(backup, mid+1, endIndex, a);
			merge(backup,startIndex,mid+1,endIndex,a);
		}
	} 
	
	private static void merge(int[] backup ,int startIndex,int midIndex,int endIndex,int[] a){
		int j = 0;
		int start = startIndex;
		int mid = midIndex-1;
		int n = endIndex-startIndex+1 ;//当前数组的长度
		//下面是排序合并
		//当比较的两半都有数据,即下标小于等于这一半的最大下标
		while (startIndex<=mid && midIndex<=endIndex) {
			if(a[startIndex]<a[midIndex]){
				backup[j++] = a[startIndex++];
			}else{
				backup[j++] = a[midIndex++];
			}
		}
		//当有一半比完了,把剩下没比的放到最后
		while (startIndex<=mid) {
			backup[j++] = a[startIndex++];
		}
		//当有一半比完了,把剩下没比的放到最后
		while (midIndex<=endIndex) {
			backup[j++] = a[midIndex++];
		}
		//排序合并完复制到原数组的相应段落位置上
		for(j=0;j<n;j++){
			a[start+j] = backup[j] ;
		}
	}
	
	/**
	 * 名称:希尔排序
	 * 顺序:从小到大
	 * 逻辑:就是插入排序,只不过把比较间隔由1变成了更大的数,把间隔相同的数排序,然后缩小间隔直到比较间隔为1
	 * 取间隔的公式又叫间隔序列公式(h = h * 3 + 1),用这个公式递归,知直到h为小于数组长度的最大数
	 * 原则:插入排序,当间隔大时,比较操作少,移位操作远。已经基本有序。当间隔小时,比较操作少,移位操作少
	 * 例子:假如数组为{8,4,2,7,9,10,30,32,5,11},长度10
	 * 那么间隔序列为4,1(用4计算可知下一个数为13,间隔比数组长度还大,不用比了。所以是4,1)
	 * 先4增量排序
	 * 9.8不动(8<9),10.4不动,30.2不动,32.7不动,5.9换位置{8,4,2,7,5,10,30,32,9,11}
	 * 既然9位置的数变小了,那要再比较一次9.8,现在变成了5.8比较,换位置{5,4,2,7,8,10,30,32,9,11}
	 * 接着刚才的5.9,11.10不动。4增量排序结束。整个过程换了895的位置,减少了插入排序位置移动的次数
	 * 再1增量排序,也就是插入排序
	 */
	public static void shellSort(int[] a){
		int inner ,outer,temp;
		int h = 1 ;
		int arrLengthDecideThree = (a.length) / 3;
		//用间隔序列公式(h = h * 3 + 1)取小于数组长度的最大序列数
		//1,4,13,40,121……
		while(h<=arrLengthDecideThree){
			h = h * 3 + 1;
		}
		//用最大h增量排序,完成一次,用公式h = (h-1)/3取第二大序列数,再进行增量排序
		//递减h,直到h等于1。……13,4,1
		//一次循环是同一类增量排序,最后一次为1增量,也就是插入排序
		while(h>0){
			//跟插入排序一样,从第二个数开始,依次往左比较,
			//这里的第二个数下标为,第一个数下标0+增量h,往左比较完,就取第三个数,也就是h+1……
			for(outer=h;outer<a.length;outer++){
				temp = a[outer] ;
				inner = outer ;
				//假如有10个数,那么就先用4增量,分别比较a[4]a[0],a[5]a[1],a[6]a[2],a[7]a[3]
				//当inner++到8的时候,比较a[8]a[4],如果a[4]小于a[8],那就比较[9][5]
				//如果a[4]大于a[8],那就把两个互换,得到较小的a[4],再a[4]a[0]比较
				while (inner>h-1 && a[inner-h]>=temp) {
					a[inner] = a[inner-h] ;
					inner = inner - h ;
				}
				a[inner] = temp ;
			}
			h = (h-1) / 3 ;
		}
	}
	
	
	/**
	 * 名称:快速排序
	 * 顺序:从小到大
	 * 逻辑:把数组分成小于最后一个数的一边和大于最后一个数的一边,找到最后一个数的位置。然后被分出来的两边继续这样操作。
	 * 原则:递归分成大小两边,当两边同时阻塞,互换元素位置。
	 * 例子:假如数组为{8,4,2,7,9,10,30,32,5,11},长度10
	 * 分成大于11和小于11的两块
	 * 左边{8,4,2,7,9,10}遇到30阻塞,右边直接就遇到5阻塞了,把30跟5换位,{8,4,2,7,9,10,5,32,30,11}
	 * 左边{8,4,2,7,9,10,5}遇到32阻塞,右边{32,30}遇到5阻塞,这时候整个数组都跟11比过一次了
	 * 把11跟32的位置互换{8,4,2,7,9,10,5,11,30,32},找到了11的位置,不会再改变。
	 * 下面继续这样处理11左边,和11右边的。
	 */
	public static void quickSort(int[] a){
		_quickSort(0,a.length-1, a);
	}
	private static void _quickSort(int left,int right,int[] a){
		if(right-left<=0){
			return ;
		}else{
			int lastElement = a[right];
			int lastElementFixIndex = parition(left,right,lastElement,a);
			//从上面得到的数位置把数组分成两段,递归上面的操作
			_quickSort(left, lastElementFixIndex-1, a);
			_quickSort(lastElementFixIndex+1, right, a);
		}
	}
	private static int parition(int left,int right,int lastElement,int[] a){
		int _left = left -1 ;
		int _right = right ;
		 while(true){
			 //直到遇到大的数停止
			 while(a[++_left]<lastElement){}
			//直到遇到小的数停止
			 while(_right>0 && a[--_right]>lastElement){}
			 //整个数组都处理完了,跳出循环
			 if(_left>=_right){
				 break;
			 }else{
				 //大的数和小的数位置互换,小的放左边。继续进入while(true),加_left,减_right,直到break
				 swap(_left,_right,a);
			 }
		 }
		 //_left>=_right,break时,_left位置的数其实是大于right位置的数,因为他是遇到大的才停止。
		 //换位置,这个基数找到了自己的位置,且之后不再变化,返回下标
		 swap(_left,right,a);
		 return _left ;
	}
	
	private static void swap(int index1,int index2,int[] a){
		int temp = a[index1] ;
		a[index1] = a[index2] ;
		a[index2] = temp ;
	}
	
	public static void main(String[] args) {
		int[] a = { 4, 5, 6, 3, 8, 1, 9 };
		shellSort(a);
		for (int b : a) {
			System.out.print(b);
		}
		
		int[] c = { 4, 5, 6, 3, 8, 1, 9 };
		quickSort(c);
		for (int b : c) {
			System.out.print(b);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值