现在的位置: 首页 > 综合 > 正文

几种常用排序

2017年11月11日 ⁄ 综合 ⁄ 共 6626字 ⁄ 字号 评论关闭

1,插入排序

原理类似于取扑克牌,从牌堆里取出扑克牌和手里的牌比较后,按照次序放好。java实现代码,最开始为了模拟取牌过程,设置了两个数组,后来改为一个,因为每次操作都不会过哨兵值K的位置。


import java.util.Scanner;


public class InsertSortDemo {
	public static void main(String args[]){
		Scanner scanner=new Scanner(System.in);
		int a[] = null,index=0;
		String numstr[]=scanner.nextLine().split(" ");
		a=new int[numstr.length];
		for(String num:numstr){
			a[index++]=Integer.parseInt(num);
		}
		int k;
		for(int j=1;j<a.length;j++){
			k=a[j];  //哨兵位置
			int i=j-1;   //哨兵位置以前的那个位置
			while(i>=0&&a[i]>k){   //逐次和前面的值比较
				a[i+1]=a[i];   //移动a[i]到a[i+1]的位置
				i--;
			}
			a[i+1]=k;   //找到合适的位置并插入
		} 
		for(int y:a){
			System.out.print(y+ " ");
		}
	}
}

1.1折半插入排序

在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素大,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。

/*
 * 折半插入排序(二分插入排序)
 * */
public class BinaryInsertionSort {
	public static void main(String args[]){
		int a[]={1,4,5,7,8,2,3,6,9};
		for(int i=1;i<a.length;i++){
			sort(a,0,i-1,i);
		}
		print(a);
	}
	/*
	 * low,high已经排好序的插入区间,正要插入的元素*/
	public static void sort(int a[],int low,int high,int k){
		if(low<=high){
			int m=(low+high)/2;
			if(a[k]<=a[m])	sort(a,low,m-1,k);
			else sort(a,m+1,high,k);
		}else{
			//备份a[k]
			int temp=a[k];
			//在0-k的区间内,把high+1以及以后的元素全部向后移动一个位置,在high+1的位置插入temp
			for(int i=k;i>high+1;i--){
				a[i]=a[i-1];
			}
			//插入temp
			a[high+1]=temp;
		}
	}
	public static void print(int a[]){
		for(int i=0;i<a.length;i++)
			System.out.print(a[i]+" ");
	}
}

1.2希尔排序


2,冒泡排序

每次将最大的数排到数组的后面,假如数组的长度为n,需要比较的趟数就是n-1:每次比较中需要遍历到的元素下标为n-j-1(j为比较趟数,从o开始)。

import java.util.Scanner;


public class BubbleSortDemo {
	public static void bubbleSort(int a[]){
		for(int j=0;j<a.length-1;j++)    //比较趟数
			for(int i=0;i<a.length-j-1;i++) //一次比较中的操作
				if(a[i]>a[i+1]) {int t=a[i];a[i]=a[i+1];a[i+1]=t;}
	}

	public static void main(String[] args) {
			Scanner scanner=new Scanner(System.in);
			String numStr[]=scanner.nextLine().split(" ");
			int i=0,a[]=new int[numStr.length];
			for(String num:numStr){
				a[i++]=Integer.parseInt(num);
			}
			bubbleSort(a);
			for(int x:a){
				System.out.print(x+" ");
			}
	}

}

2.1堆排序

import java.math.MathContext;

/*
 * 堆排序(最大堆树要满足一个条件就是每一个结点值都要大于或等于它的孩子结点值。在一个数组中那专业法表示为:

arrays[i]>=arrays[2*i+1] && arrays[i]>=arrays[2*i+2]; )
 * 堆排序适合于大量数据的排序,堆排序的前续工作花费的时间比较多,下面我们以大根堆为例说说: 
大根堆,就是根节点是最大的元素,所以每次把最大的元素选出来,与最后的一个元素交换,然后再把前n-1个元素(也就是除最后一个元素)进行一个堆的重构,让其具有大根堆的性质,重复上面的过程,直到只剩一个元素为止。这个过程其实是个选择排序的过程,但是少了交换的次数,堆排序的时间复杂度是nlogn。*/
public class HeapSort {

	public static void main(String args[]){
		int a[]={5,8,2,3,5,7,15,9,23};
		for(int i=a.length-1;i>0;i--)
			sortFindMax(a,i);
		print(a);
	}
	
	//计算log2(x)
	public static int log2(double x){
		return  (int) (Math.log(x)/Math.log(2));
	}
	
	//找出0-n之间的最大值并发到数组末尾
	public static void  sortFindMax(int a[],int n){
		int zhishu=log2(n+1);
		int l=(int) (Math.pow(2, zhishu)-2);
		for(int i=0;i<=l;i++){
			check(a,i,n);
		}
		swap(a,0,n);
	}
	
	public static void swap(int a[],int i,int j){
		int temp=a[i];
		a[i]=a[j];
		a[j]=temp;
	}
	
	//检测,发现不满足最大堆树,交换位置。
	public static void check(int a[],int k,int n){
		//先和孩子节点比较
		int parent=(k-1)/2;
		int left=2*k+1;
		int right=2*k+2;
		
		if(left<=n&&a[left]>a[k]) swap(a,left,k);
		if(right<=n&&a[right]>a[k]) swap(a,right,k);
		if(a[k]>a[parent]) swap(a,parent,k);
	}
	
	public static void print(int a[]){
		for(int i=0;i<a.length;i++)
			System.out.print(a[i]+" ");
	}
}


3,快速排序

选取一个k值,左右扫描,找出比k大的放在k右边,比k小的放在k左边。然后再对k左右两边的分别排序。

import java.util.Scanner;


public class QuickSortDemo {

	public static void quickSort(int a[],int begin,int end){
		int i=begin,j=end,temp;
		while(i<j){
			while(i<j&&a[j]>=a[i]){  //从右侧开始扫描,k在a[i]处
				j--;
			}
			if(i<j){   //找出第一个比k小的,交换位置
				temp=a[i];
				a[i]=a[j];
				a[j]=temp;
			}
			while(i<j&&a[i]<=a[j]){  //从左侧开始扫描,k在a[j]处
				i++;
			}
			if(i<j){	//找出第一个比k大的,交换位置
				temp=a[i];
				a[i]=a[j];
				a[j]=temp;
			}
		}
		//k在a[i]处
		if(i-1-begin>0){
			quickSort(a,begin,i-1);
		}
		if(end-(i+1)>0){
			quickSort(a,i+1,end);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scanner=new Scanner(System.in);
		String numStr[]=scanner.nextLine().split(" ");
		int i=0,a[]=new int[numStr.length];
		for(String num:numStr){
			a[i++]=Integer.parseInt(num);
		}
		quickSort(a,0,a.length-1);
		for(int x:a){
			System.out.print(x+" ");
		}
	}

}

4,归并排序

来源于分治思想,把排序划分为若干个排序的子问题,最小划分为1,比如:

1 6 9 2 5 7排序,就可以划分为[1 6 9] [2 5 7],排好后再合并。

代码:

import java.util.Scanner;

public class MergeSortDemo {
	public static void merge(int a[], int p, int r, int q) {
		int b[] = new int[r-p+1], c[] = new int[q-r];
		// 拷贝数组
		System.arraycopy(a, p, b, 0, r - p+1);
		System.arraycopy(a, r+1, c, 0, q - r );
		int i = 0, j = 0, t = 0;
		while (i < b.length && j < c.length) {
			if (b[i] < c[j]) {
				a[p + t] = b[i];
				i++;
			} else {
				a[p + t] = c[j];
				j++;
			}
			t++;
		}
		while (i < b.length) {
			a[p + t] = b[i];
			i++;
			t++;
		}
		while (j < c.length) {
			a[p + t] = c[j];
			j++;
			t++;
		}
	}

	public static void mergeSort(int a[], int p, int q) {
		int mid;
		if (p < q) {
			mid = (p+q) / 2;
			mergeSort(a,p,mid);
			mergeSort(a,mid+1,q);
			merge(a,p,mid,q);
		}
	}

	public static void main(String args[]) {
		Scanner scanner=new Scanner(System.in);
		String numstr[]=scanner.nextLine().split(" ");
		int a[]=new int[numstr.length];
		int i=0;
		for(String num:numstr){
			a[i++]=Integer.parseInt(num);
		}
		mergeSort(a,0,a.length-1);
		for(int x:a){
			System.out.print(x+" ");
		}
	}

}

5,基数排序

第一步

以LSD为例,假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39

第二步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93

第三步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class DistrSort {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[]={123,3456,1,3,5,8,90,12,345,15,19};
		int maxW=findMaxW(a);
		for(int i=1;i<=maxW;i++)
			sort(a,i);
		print(a);
	}
	
	/*k代表排序的位数,最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。*/
	public static void sort(int a[],int k){
		Map<Integer,List> map=new HashMap<Integer,List>();
		
		//放入相应的木桶
		for(int i=0;i<a.length;i++){
			int w=((int)(a[i]/Math.pow(10, k-1)))%10;
			List<Integer> list=map.get(w);
			if(null==list){
				list=new ArrayList<Integer>();
			}
			list.add(a[i]);
			if(null!=list)	map.put(w, list);
		}
		
		int j=0;
		//将木桶解析还原成数组
		for(int i=0;i<=9;i++){
			List<Integer> list=map.get(i);
			if(null!=list){
				for(Integer e:list)
					a[j++]=e;
			}
		}
	}
	
	public static void print(int a[]){
		for(Integer e:a){
			System.out.print(e+" ");
		}
	}
	
	/*找到最大的位*/
	public static int findMaxW(int a[]){
		int maxW=0;
		for(Integer e:a){
			String num=e+"";
			if(maxW<num.length()) maxW=num.length();
		}
		return maxW;
	}
}

6,计数排序

时间复杂度是线性的,不是基于比较的排序。

1,扫描整个数组,找出最大值和最小值。

2,构造一个辅助数组,用于标记某个元素是否存在。

3,从小往大累加,算出某个元素前面有多少数。

4,按照各自的位置放入另一个数组。

/*该代码中不能存在相同的元素*/
public class CountSort {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[]={3,78,12,345,2,90,234,56};
		int b[]=sort(a);
		print(b);
	}

	public static int[] sort(int a[]){
		int b[]=new int[a.length];
		int max=a[0],min=a[0];
		//找出最大值和最小值
		for(Integer e:a){
			if(e>max) max=e;
			if(e<min) min=e;
		}
		int k=max-min+1;  //算出极差值
		int c[]=new int[k];
		for(int i=0;i<a.length;i++)
			c[a[i]-min]=1;
		
		//累积计算出比自己小的数量
		for(int i=1;i<c.length;i++)
			c[i]+=c[i-1];
		
		//把a[]按位置放入b[]
		for(int i=0;i<a.length;i++)
			b[c[a[i]-min]-1]=a[i];
		return b;
	}
	
	public static void print(int a[]){
		for(Integer e:a){
			System.out.print(e+" ");
		}
	}
}

要熄灯了,改天再总结其他排序。

抱歉!评论已关闭.