排序算法总结

总结一下所学的排序算法。

一、冒泡排序

从小到大排序,思想:遍历数组,下一个元素比当前元素大就交换,这样经过一轮后,把最大元素排到了最后,经过n-1轮,就把n-1大的元素排到了数组最后,最小值默认就排到了第一个位置。

时间复杂度:最坏O(n^2),最好是O(n)(可以用一个标记,第一趟如果没交换,说明数组是有序的),比较次数与原始数组无关。

/**  
 * @Title:  BubbleSort.java   
 * @Package com.lian   
 * @Description:    TODO()   
 * @author: Lian
 * @date:   2018年7月15日 上午10:02:04   
 * @version V1.0  
 */
    
package com.lian;
public class BubbleSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[]= {3,1,5,7,10,2,4,6,8,9};
		int n=a.length;
		for(int i=0;i<n-1;i++) {
			//每次把最大的元素排到了数组末尾
			boolean flag=false;//标记
			for(int j=0;j<n-i-1;j++) {
				if(a[j]>a[j+1]) {
					int temp=a[j];
					a[j]=a[j+1];
					a[j+1]=temp;
					flag=true;
				}
			}
			if(flag==false)break;
		}
		for(int i=0;i<n;i++) {
			System.out.print(a[i]+" ");
		}
		System.out.println();
	}

}

二、选择排序

从小到大排序,思路:A[1...i]有序后,从余下数组中选择最小的元素排到A[i+1],进行n-1次后选出了n-1个最小值,最后一个默认就是最大值。

时间复杂度:最坏/最好都是Θ(n^2),比较次数与原始数组无关。

/**  
 * @Title:  SelectionSort.java   
 * @Package com.lian   
 * @Description:    TODO()   
 * @author: Lian
 * @date:   2018年7月15日 上午9:54:00   
 * @version V1.0  
 */
    
package com.lian;
public class SelectionSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[]= {3,1,5,7,10,2,4,6,8,9};
		int n=a.length;
		for(int i=0;i<n-1;i++) {
			int min=a[i];
			int id=i;
			for(int j=i+1;j<n;j++) {
				if(min>a[j]) {
					min=a[j];
					id=j;
				}
			}
			int temp=a[id];a[id]=a[i];a[i]=temp;
		}
		for(int i=0;i<n;i++) {
			System.out.print(a[i]+" ");
		}
		System.out.println();
	}

}

三、插入排序

从小到大排序思路:将a[j]插入到a[0...j-1]中,即a[0...j-1]有序后,将a[j]插入到a[0...j-1]中。

时间复杂度:最坏O(n^2),最好O(n)(有序),比较次数与原始数组无关

/**  
 * @Title:  InsertionSort.java   
 * @Package com.lian   
 * @Description:    TODO()   
 * @author: lian
 * @date:   2018年6月26日 下午9:27:32   
 * @version V1.0  
 */
    
package com.lian;

public class InsertionSort {
	
	public static void main(String[] args) {
		
		int i,j;
		int a[]= {3,1,5,7,10,2,4,6,8,9};
		for( j=1;j<a.length;j++) {
			//insert a[j] into the sorted sequence a[0...j-1]
			int temp=a[j];
			for(i=j-1;i>=0;i--) {
				if(a[i]>temp) {
					a[i+1]=a[i];
				}
				else break;
			}
			a[i+1]=temp;
		}
		for(i=0;i<a.length;i++)
		{
			System.out.print(a[i]+" ");
		}

	}

}

四、归并排序

从小到大排序思路:分治的思想,将数组递归的平分为两部分,回溯过程中归并,归并方法是将左右两部分排好序的数组,归并到原来a数组,此区间便是有序的了。

时间复杂度:Θ(nlgn)

package com.lian;

public class MergeSort {

	public void merge(int[] a,int p,int q,int r) {
		int i,j;
		int n1=q-p+1;
		int n2=r-q;
		int[] L=new int[n1+1];
		int[] R=new int[n2+1];
		for(i=0;i<n1;i++) {
			L[i]=a[p+i];
		}
		for(j=0;j<n2;j++) {
			R[j]=a[q+1+j];
		}
		L[n1]=R[n2]=10000000;//多出一位,下面程序的比较中会体现。
		i=0;j=0;
		for(int k=p;k<=r;k++) {
			if(L[i]>R[j]) {
				a[k]=R[j];
				j++;
			}
			else {
				a[k]=L[i];
				i++;
			}
		}
	}
	public void mergeSort(int[] a,int p,int r) {
		if(p<r)
		{
			int q=(p+r)>>1;
			mergeSort(a,p,q);
			mergeSort(a,q+1,r);
			merge(a,p,q,r);
		}
	}
	public static void main(String[] args) {
		int i;
		int a[]= {3,1,5,7,10,2,4,6,8,9};
		new MergeSort().mergeSort(a, 0, a.length-1);
		for(i=0;i<a.length;i++) {
			System.out.print(a[i]+" ");
		}
		
	}

}

五、快排

被认为是最好的排序方法,从小到大思想:分治思想,选择一个轴(一个标准点),将小于此值的元素划分到左支,大于此元素的划分到右支。一直这样划分下去,到叶节点便是有序的了。

时间复杂度:  当数据组有序或者无序时,时间复杂度T(n)=T(n-1)+Θ(n)=Θ(n^2);
                      如果最后一个元素都能使划分最好,那么T(n)=2*T(n/2)+Θ(n)=Θ(nlgn);
                      任意划分,如:T(n)=T(9n/10)+T(n/10)+Θ(n)=Θ(nlgn);

                      因此,期望时间复杂度Θ(nlgn)

/**  
 * @Title:  QuickSort.java   
 * @Package com.lian   
 * @Description:    TODO()   
 * @author: Lian
 * @date:   2018年7月11日 下午9:38:25   
 * @version V1.0  
 */
    
package com.lian;
/**
 * 当数据组有序或者无序时,时间复杂度T(n)=T(n-1)+Θ(n)=Θ(n^2);
 * 如果最后一个元素都能使划分最好,那么T(n)=2*T(n/2)+Θ(n)=Θ(nlgn);
 * 任意划分,如:T(n)=T(9n/10)+T(n/10)+Θ(n)=Θ(nlgn);
 * 因此,期望时间复杂度Θ(nlgn)
 */
public class QuickSort {
	public static int partition(int[] a,int q,int r) {
		//选最后一个元素作为枢纽,可以随机选一个元素。
		int x=a[r];
		int i=q-1;
		for(int j=q;j<r;j++) {
			if(a[j]<x) {
				i++;
				int temp=a[i];a[i]=a[j];a[j]=temp;
			}
		}
		i++;
		int temp=a[i];a[i]=a[r];a[r]=temp;
		return i;
	}
	public static void quickSort(int[] a,int q,int r) {
		if(q<r) {
			int index=partition(a,q,r);
			quickSort(a, q, index-1);
			quickSort(a, index+1, r);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int [] a= {5,4,6,7,8,3,1,2,9,10,1232,34,56,777,44,22};
		quickSort(a,0,a.length-1);
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i]+" ");
		}
		System.out.println();
	}

}
//非递归实现,主要就是利用栈来模拟递归,每次存入一对左右边界
void quickSort(int[] array,int left,int right) {
	stack<Integer> sta;
	sta.push(left);
	sta.push(right);
	while(!sta.empty()) {
		int r = sta.pop();
		//sta.pop();
		int l = sta.pop();
		//sta.pop();
		
		int index = partition(array, l, r);
		if(index - 1 > l) {
			sta.push(l);
			sta.push(index - 1);
		}
		if(index + 1 < r) {
			sta.push(index + 1);
			sta.push(r);
		}
	}
}

六、堆排序

从大到小排序,即最大堆思想:a[parent(i)]>=a[i],父节点元素永远大于或等于子元素。

时间复杂度:O(nlgn),假设有n个元素,那么树高为O(lgn)。

维护最大堆MAX-HEAPIFY过程:O(lgn)

建树BUILD-MAX-HEAP过程:线性时间复杂度,从无序的输入数组中构造一个最大堆。证明见算法导论

排序HEAPSORT过程:O(nlgn),功能是堆一个数组进行原址排序(即不需要额外空间)。

同理可以构造个优先队列。



/**  
 * @Title:  HeapSort.java   
 * @Package com.lian   
 * @Description:    TODO()   
 * @author: Lian
 * @date:   2018年7月11日 上午10:58:11   
 * @version V1.0  
 */
    
package com.lian;
/**  
 * 堆排序和插入排序是in place(即不需要额外的内存空间);
 */
public class HeapSort {
	public static void maxHeapify(int[] a,int i,int length)
	{
		int left=i<<1;
		int right=i<<1|1;
		//在i,left,right找出最大的值
		int largest=i;
		if(left<=length&&a[left]>a[i]) {
			largest=left;
		}
		if(right<=length&&a[right]>a[largest]) {
			largest=right;
		}
		if(largest!=i) {
			int temp=a[i];
			a[i]=a[largest];
			a[largest]=temp;
			maxHeapify(a,largest,length);
		}
	}
	public static void buildMaxHeap(int[] a,int length) {
		for(int i=length/2;i>=1;i--) {
			maxHeapify(a,i,length);
		}
	}
	public static void heapSort(int[] a,int length) {
		buildMaxHeap(a,length);
		for(int i=1;i<a.length;i++)
			System.out.print(a[i]+" ");
		System.out.println();
		for(int i=length;i>=2;i--) {
			int temp=a[1];a[1]=a[i];a[i]=temp;
			length--;
			maxHeapify(a,1,length);
			
		}
	}
	/**
	 * @Description: TODO(优先队列)
	 */
	//返回堆顶元素
	public static int heapMaxMum(int[] a) {
		return a[1];
	}
	//返回堆顶元素并删除
	public static int heapExtractMax(int[] a,int length) {
		if(length<1) {
			System.out.println("队列为空");
			return -1;
		}
		int max=a[1];
		a[1]=a[length];
		length--;
		maxHeapify(a,1,length);
		return max;
	}
	//数组的第i个元素置为key
	public static void insertKey(int[] a,int i,int key)
	{
		if(key<a[i]) {
			System.out.println("key不能小于其值");
			return;
		}
		a[i]=key;
		while(i>1&&a[i/2]<a[i]) {
			int temp=a[i/2];a[i/2]=a[i];a[i]=temp;
			i/=2;
		}
	}
	//插入一个元素
	public static void insert(int[] a,int value,int length) {
		length++;
		a[length]=-1000000;
		insertKey(a,length,value);
	}
	public static void priorityQueue(int[] que,int length)
	{
		buildMaxHeap(que, length);
		System.out.println("建树后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
		int top=heapMaxMum(que);
		System.out.println("top:"+top);
		int pop=heapExtractMax(que, length--);
		System.out.println("pop:"+pop+"  length:"+length);
		System.out.println("弹出元素后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
		insert(que,111,length);
		length++;
		System.out.println("插入元素后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
	}
	public static void main(String[] args) {
		int a[]= {-100000,3,1,5,7,10,2,4,6,8,9};
		/*堆排序*/
//		heapSort(a,a.length-1);
//		for(int i=1;i<a.length;i++)
//		System.out.print(a[i]+" ");
		
		/*优先队列*/
		int[] que=new int[100];
		for(int i=0;i<a.length;i++) {
			que[i]=a[i];
		}
		priorityQueue(que,a.length-1);
	}


}	public static void maxHeapify(int[] a,int i,int length)
	{
		int left=i<<1;
		int right=i<<1|1;
		//在i,left,right找出最大的值
		int largest=i;
		if(left<=length&&a[left]>a[i]) {
			largest=left;
		}
		if(right<=length&&a[right]>a[largest]) {
			largest=right;
		}
		if(largest!=i) {
			int temp=a[i];
			a[i]=a[largest];
			a[largest]=temp;
			maxHeapify(a,largest,length);
		}
	}
	public static void buildMaxHeap(int[] a,int length) {
		for(int i=length/2;i>=1;i--) {
			maxHeapify(a,i,length);
		}
	}
	public static void heapSort(int[] a,int length) {
		buildMaxHeap(a,length);
		for(int i=1;i<a.length;i++)
			System.out.print(a[i]+" ");
		System.out.println();
		for(int i=length;i>=2;i--) {
			int temp=a[1];a[1]=a[i];a[i]=temp;
			length--;
			maxHeapify(a,1,length);
			
		}
	}
	/**
	 * @Description: TODO(优先队列)
	 */
	//返回堆顶元素
	public static int heapMaxMum(int[] a) {
		return a[1];
	}
	//返回堆顶元素并删除
	public static int heapExtractMax(int[] a,int length) {
		if(length<1) {
			System.out.println("队列为空");
			return -1;
		}
		int max=a[1];
		a[1]=a[length];
		length--;
		maxHeapify(a,1,length);
		return max;
	}
	//数组的第i个元素置为key
	public static void insertKey(int[] a,int i,int key)
	{
		if(key<a[i]) {
			System.out.println("key不能小于其值");
			return;
		}
		a[i]=key;
		while(i>1&&a[i/2]<a[i]) {
			int temp=a[i/2];a[i/2]=a[i];a[i]=temp;
			i/=2;
		}
	}
	//插入一个元素
	public static void insert(int[] a,int value,int length) {
		length++;
		a[length]=-1000000;
		insertKey(a,length,value);
	}
	public static void priorityQueue(int[] que,int length)
	{
		buildMaxHeap(que, length);
		System.out.println("建树后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
		int top=heapMaxMum(que);
		System.out.println("top:"+top);
		int pop=heapExtractMax(que, length--);
		System.out.println("pop:"+pop+"  length:"+length);
		System.out.println("弹出元素后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
		insert(que,111,length);
		length++;
		System.out.println("插入元素后:");
		for(int i=1;i<=length;i++) {
			System.out.print(que[i]+" ");
		}
		System.out.println();
	}
	public static void main(String[] args) {
		int a[]= {-100000,3,1,5,7,10,2,4,6,8,9};
		/*堆排序*/
//		heapSort(a,a.length-1);
//		for(int i=1;i<a.length;i++)
//		System.out.print(a[i]+" ");
		
		/*优先队列*/
		int[] que=new int[100];
		for(int i=0;i<a.length;i++) {
			que[i]=a[i];
		}
		priorityQueue(que,a.length-1);
	}


}

七、计数排序、基数排序、桶排序

都是线性时间的排序。

计数排序:在元素值不是很大时可以用,对每一个元素x,确定小于x的元素个数。利用这一信息可以直接把x放到它在输出数组中的位置上。

基数排序:本质就是将每个数值分解成x位,然后,从低位->高位排序。

桶排序:假设输入数据均匀、独立分布在[0,1)区间上,平均情况下它的时间代价为O(n),将[0,1)区间划分为n个大小相同的子区间(“桶”)。然后,将n个输入元素分别方法各个桶中。因为是均匀分布,所以不会出现一个桶有很多元素的情况。然后,一次对每个桶中的元素进行排序,然后遍历每个桶,按照次序把每个桶中的元素列出来。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值