Java各种排序

考虑几种简单的排序算法

冒泡排序

策略:每次比较相邻两个元素的大小,大的往后放。这样一次循环之后,最大的元素就被放到了最后面,那么下次排序只需要从1~N-1这些元素进行下一次排序

public static void bubble_Sort(int[] A,int N) {
		for(int p=N-1;p>0;p--) {
			int flag=0;
			for(int i=0;i<p;i++) {
				if(A[i]>A[i+1]) {
					int tmp=A[i];
					A[i]=A[i+1];
					A[i+1]=tmp;
					//Swap(A[i],A[i+1])
					flag=1;
				}
			}
			if(flag==0) break;//flag==1  数组排序完成,不需要接下来的操作
		}
	}

需要注意的地方:如果我们的数组本来就是顺序的,或者说执行几次循环之后成了顺序的,后面的操作就没有必要进行下去。在里面我们设置了一个flag在外循环设置它为0,在同一深度中分别执行 int flag=0;交换操作;以及判定flag,当某一次循环时候如果出现了全部升序的情况,说明数组排序好了,这时候flag也不会变成1,那么接下来的操作就不用继续了所以break

  • 稳定性:两个相邻的数如果相等,不会执行交换,相对位置不会破坏,稳定性满足。
  • 时间复杂度:最好情况–数组刚好完全正序:T=O(N);最坏情况–数组刚好完全倒序:T=O(N2);

插入排序

策略:类似于我们打牌克的抽牌,每次我们按顺序抽取其中的一张牌,然后将这张牌和前面的所有牌进行比较,直到满足 A[i-1]<tmp<=A[i]=A[i+1];

public static void insertion_Sort(int[] A,int N) {
		int i;
		for(int p=1;p<N;p++) {
			int tmp=A[p];
			for(i=p;i>0&&A[i-1]>tmp;i--) 
				A[i]=A[i-1];
			A[i]=tmp;
		}
	}

需要注意的地方;我们的操作相当于是把某一位置i的牌拿起来把他和前面的牌比较大小,直到满足上面给出的不等式,这时候A[i]覆盖了A[i+1],所以A[i]=A[i+1],而我们要做的就是把我们的临时变量tmp(保存了原来拿起的那张牌的值)的值赋给A[i];

  • 稳定性:假设我们原来的数组中有a=b,并且a与b相邻那么当我们插入的时候先插入b,然后插入a 根据上面写出来的不等式必须满足 a<=b;(由于执行循环的时候b>a不满足,所以把a放到b前面),所以稳定性满足。
  • 时间复杂度:最好情况–刚好正序;T=O(N);最坏情况–刚好倒序T=O(N2);

逆序对和两个定理

逆序对:对于下标i<j,如果A[i]>A[j],称(i,j)是一对 逆序对

问题:序列{34,8,64,51,32,21}中有多少逆序对?
答案:(34,8)(34,32)(34,21)(64,51)(64,32)(64,21)(51,32)(51,21)刚好是9对,而且会发现使用冒泡排序和插入排序交换次数也刚好是9次,是因为执行冒泡排序的时候每次交换相邻元素就会消去一个逆序对。

  • 定理:任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对
  • 定理:任意仅以交换相邻元素来排序的算法,其时间复杂度下界 Ω(N2);

希尔排序

原始的希尔排序

原始增量:Dk=└ Dk+1/2┘

public static void shell_Sort(int[] A,int N) {
		for(int D=N/2;D>0;D/=2) {/*希尔增量序列--*/
			for(int P=D;P<N;P++) {/*插入排序*/
				int Tmp=A[P];
				int i;
				for(i=P;i>=D&&A[i-D]>Tmp;i-=D)
					A[i]=A[i-D];
				A[i]=Tmp;
			}
		}
	}
  • 最坏时间复杂度 :T=θ(N2
Hibbard增量序列

Hibbard增量:Dk=2k-1 相邻元素互质

  • 最坏情况 T=θ(N2/3
  • 猜想:Tavg=O(N5/4)
Sedgewick 增量序列

{1,5,19,41,109} Sedgewick 增量:4i-3*2i+1

  • 最坏情况:Tworst=O(N4/3)
  • 猜想:Tavg=O(N7/6)

堆排序

堆排序会牵扯到二叉树的知识,并且实际效果不如Sedgewick 增量的希尔排序,这里暂时不写

归并排序–递归算法

策略:分而治之,递归算法会使用大量的额外堆栈空间。

在这里插入图片描述

有序子列的归并
public static void merge(int[] A,int[] TmpA,int L,int R,int RightEnd) {
		int LeftEnd=R-1;
		int Tmp=L;
		int num=RightEnd-L+1;
		
		while((L<=LeftEnd)&&(R<=RightEnd)) {
			if(A[L]<A[R]) TmpA[Tmp++]=A[L++];
			else          TmpA[Tmp++]=A[R++];  
		}
		while(L<=LeftEnd)
			TmpA[Tmp++]=A[L++];
		while(R<=RightEnd)
			TmpA[Tmp++]=A[R++];
		
		for(int i=0;i<num;i++,RightEnd--)
			A[RightEnd]=TmpA[RightEnd];
	}
  • L=左边起始位置
  • R=右边起始位置
  • RightEnd=右边终点位置
  • LeftEnd=左边终点位置
  • Tmp=TmpA中充当指针
  • num=数组中归并的总数
  • L不为0是为了后面的操作
递归实现子序列合并
public static void mSort(int[] A,int[] TmpA,int L,int RightEnd) {
		int center;
		if(L<RightEnd) {
			center=(L+RightEnd)/2;
			mSort(A,TmpA,L,center);
			mSort(A,TmpA,center+1,RightEnd);
			merge(A,TmpA,L,center+1,RightEnd);
		}
	}

需要注意的地方:if(L<RightEnd)是为了判定L到RightEnd之间的元素个数

合并算法–递归

现在我们把算法转化为标准格式X_Sort(ElementType A[],int N)

public static void merge1_Sort(int[] A,int N) {
		int[] TmpA=new int[N];
		if(TmpA!=null) {
			mSort(A,TmpA,0,N-1);
		}
	} 

归并排序–非递归算法

子序列合并
public static void merge_Pass(int[] A,int[] TmpA,int N,int length) {
		int i;
		int j;
		for(i=0;i<N-2*length;i+=2*length) 
			merge(A,TmpA,i,i+length,i+2*length-1);
		if(i+length<N)
			merge(A,TmpA,i,i+length,N-1);
		else
			for(j=i;j<N;j++)
				TmpA[j]=A[j];
	}
合并算法–非递归
public static void merge2_Sort(int[] A,int N) {
		int[] TmpA=new int[N];
		int length=1;
		if(TmpA!=null) {
			while(length<N) {
				merge_Pass(A,TmpA,N,length);
				length*=2;
				merge_Pass(TmpA,A,N,length);
				length*=2;
			}
		}
	}

需要注意的地方:两种算法都需要额外的堆栈空间存储,但是两者都是稳定的,并且时间复杂度都是N*logN

快速排序

策略:分而治之 搬运自此处

/*快速排序---分而治之*/
	private static void function(int[] arr, int begin, int end) {
        if(begin > end) return;

        int tmp = arr[begin];
        int i = begin;
        int j = end;

        while (i != j) {
            while (arr[j] >= tmp && j > i)
                j--;
            while (arr[i] <= tmp && j > i)
                i++;
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }

        arr[begin] = arr[i];
        arr[i] = tmp;
        function(arr, begin, i - 1);
        function(arr, i + 1, end);
    }

表排序

桶排序

基数排序

多关键字排序

测试程序

public static void print(int[] array) {
		for(int tmp:array) {
			System.out.print(tmp+" ");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		int[] A={34,8,64,51,32,21};
		//对比查看排序前后数组的变化
		print(A);
		//insertion_Sort(A,A.length);
		//bubble_Sort(A, A.length);
		//merge1_Sort(A,A.length);
		//merge2_Sort(A,A.length);
		//shell_Sort(A,A.length);
		print(A);

		
	}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值