排序 Top ten

事实上就是十种..

这里介绍数据结构与算法里学到的十种排序算法。

由于最近在学java就用了Java来写..其实没啥子区别下面是程序主代码

package welcome;

import java.util.Scanner;
import java.util.*; 
import java.text.*;  

public class  Helloworld {   
	static void text(int a[],int n)
	{
               //排序算法
	}
	public static void main(String args[]) {    
	int []a=new int[200];
	int n;
	Scanner input=new Scanner(System.in);
	n=input.nextInt();
	for(int i=1;i<=n;i++)
		a[i]=input.nextInt();
	Helloworld.text(a,n);
	for(int element=1;element<=n;element++)
		System.out.print(a[element]+" ");
	} 
}

1-直接插入排序

直接插入排序是将数组分成有序区和无序区,把数组的第一个元素当做有序的有序区。

这里我们需要知道无序区的第一个元素,如果比有序区的最后一个元素大,则有序区扩大一个元素;反之,如果小,就往前挪,直到前面那个元素比这个元素大为止,也就是找到合适的位置。

挪的过程:把无序区第一个元素提出来,这个空间就是空的了,然后把合适位置之后的元素都往后放,R[j+1]=R[j]

复杂度显然是1+2+3+..n=n2[PS:只是粗略计算,下面也是]

static void text(int a[],int n)
{
	int j,temp;
		for(int i=2;i<=n;i++)
	{
		    if(a[i]<a[i-1])
	    {
		       temp=a[i];
	       j=i-1;
	       do
	       {
	    	   a[j+1]=a[j];
	    	   j--;
	       }while(j>=0&&a[j]>temp);
	       a[j+1]=temp;
	    }  
	}
	return ;
}

2-折半插入排序

优化直接插入排序,利用二分查找位置。

值得注意的是:这种二分方式相等就动左区间,容易把数据变大,以至于最后处理出来的结果一定是high>low导致退出循环的,也就是说插入的位置应该是high+1。

	static void text(long a[],int n)
	{
		int j,temp,low,high;long key;
        for(int i=2;i<=n;i++)
        {
        	if(a[i]<a[i-1])
        	{
        		key=a[i];
        		low=1;high=i-1;
        		while(low<=high)
        		{
        			temp=(low+high)/2;
        			if(key>=a[temp])
        			{
        				low=temp+1;
        			}
        			else high=temp-1;//相等的时候low往后动,所以low位置最后偏大,最后一步判断区间中间值过大,所以右区间向左移,但是答案是high+1
        		}
        		for(j=i-1;j>=high+1;j--)
        		{
        			a[j+1]=a[j];
        		}
        		a[high+1]=key;
        	}
        }
		return ;
	}

3-希尔排序

采用了分块的思想。

基本思想是先取一个小于n的整数d1作为第一个增量,把表的全部元素分成d1个组,将所有距离为d1作为第一个增量,把表的全部元素分成d1个组,将所有距离为d1的倍数的元素放在同一个组中。在各组内进行直接插入排序;然后取第二个增量,以此类推。所以希尔排序称为减少增量的排序方法。

每一趟希尔排序从元素R[d]开始起,采用直接插入排序,直到R[n-1]为止。每一个元素的比较和插入都在同组内部进行,对于元素R[i],同组的前面的元素有{R[j] | j=i-d>=0}。

复杂度难以计算,知道n^1.3,且总体是log(n)*d^2即可。

    public static void text(long a[],int n)
    {
    	int i,j,d=n/2;
    	long tmp;
    	while(d>0)
    	{
    		for(i=d;i<n;i++)
    		{
    			tmp=a[i];
    			j=i-d;
    			while(j>=0&&a[j]>tmp)
    			{
    				a[j+d]=a[j];
    				j-=d;
    			}
    			a[j+d]=tmp;
    		}
    		d/=2;
    	}
    }

4-冒泡排序

冒泡排序也称为气泡排序,基本思想是通过无序区的相关元素关键字间的比较和位置的交换使关键字最小的元素如同气泡一般逐渐往上飘浮直至水面。

整个算法从下面的元素开始,对每两个相邻的关键字进行比较,且使关键字较小的元素换至关键字较大的元素之上,使得经过一趟冒泡排序后关键字最小的元素到达最上端。接着,在剩下的元素中找关键字次小的元素,并把它换到第二个位置上。以此类推,直至有序。

冒泡排序需要多次排序,显然略劣于直接插入的。

    public static void text(long a[],int n)
    {
    	long temp;boolean exchange;
    	for(int i=0;i<n-1;i++)
    	{
    		exchange=false;
    		for(int j=n-1;j>i;j--)
    		{
    			if(a[j]<a[j-1])
    			{
    			  exchange=true;
    			  temp=a[j-1];
    			  a[j-1]=a[j];
    			  a[j]=temp;
    			}
    		}
		if(!exchange)return ;
    	}
    }

5-快速排序

总体思路很简单

找到一个基准,使得这个基准左边小于它,右边大于它。

递归到最后就是有序的。

实现的方式就是以第一个元素作为基准,然后两边往中间找,第一个元素显然是空的,以此类推,找到不属于这边的就换到另一边去造出新的空的地方,最后剩下的i存放我们的基准。并返回这个值,再对i左右进行分别递推。

    public static int text1(long a[],int s,int t)
    {
        long temp=a[s];
        int j=t;
        int i=s;
        while(i<j)
        {
        	while(j>i&&temp<=a[j])
        		j--;
        	a[i]=a[j];
        	while(i<j&&temp>=a[i])
        		i++;
        	a[j]=a[i];
        }//最后a[i]的值被赋走,i位置空了
        a[i]=temp;
        return i;
    }
    public static void text(long a[],int s,int t)
    {
    	int i;
    	if(s<t)
    	{
    		i=Helloworld.text1(a, s, t);
    		text(a,s,i-1);
    		text(a,i+1,t);
    	}
    }

6-简单选择排序

简单选择排序就是从无序区选出最小的元素放在无序区的第一个元素,作为有序区的新元素进行扩张。

每一次找最小的是n级别的,有序区的扩张也是n级别,所以这也是On2的算法。

    public static int text(long a[],int n)
    {
    	int k,j;
    	long temp;
    	for(int i=0;i<n-1;i++)
    	{
    		k=i;
    		for(j=i+1;j<n;j++)
    		 if(a[j]<a[k])
    			  k=j;
    	   {
    		temp=a[k];
    		a[k]=a[i];
    		a[i]=temp;
    	   }//交换
    	}
    	return 0;
    }

7-堆排序

这里关于堆

堆排序是一种树形选择排序方法,它的特点是将R[1...n](R[i]的关键字为ki)看成是一颗完全二叉树的的顺序存储结构。

利用完全二叉树中双亲节点和孩子节点之间的位置关系在无序区中选择关键字最大(最小)的元素。

堆排序和简单选择排序基本一致,都是选择最大或最小元素放进有序区,只是选择元素的方法不同,这里采用大根堆实现。

假设对R[low...high]进行筛选,必须满足前提条件,即以R[low]为根节点的左子树和右子树均为大根堆,然后对R[low]进行下降操作。一开始的数据必然是不满足的,我们需要从最后一个分支结点开始,一层层往上一步步递推建立,因为一开始必然满足条件,随着建立的过程,处理上一层的时候下一层已经被处理过满足条件,从而建立初始堆。

然后开始选择最大元素,缩小无序区,再更新堆,再不断选择到最后,形成有序的排列。

复杂度简单分析:

n个结点的完全二叉树的高度h=log2n+1;在建立初始堆的时候,需要筛选调整的层有h-1~1层,以第i层中某个节点为根的子树的高度为h-i+1,并且第i层最多有2^(i-1)个结点。

同时筛选本身的操作最坏时间:跑了h-1个循环,每个循环比较一次孩子大小和堆条件符合,所以是2(h-1)次比较。

建立初始堆:

C1(n)=\sum_{i=h-1}^{1}2^{i-1}*2(h-i+1-1)=\sum_{i=h-1}^{1} 2^{i}*(h-i)

令j = h - i,当i = h - 1时,j = 1 ;当i = 1,j = h - 1

C1(n)=\sum_{j=1}^{h-1}2^{h-j}*j=2^{h+1}-2h-2<2^{\\log_{2}{n}+1+1}<4n

错位相减的运用。

重建堆: 

C2(n)=\sum_{i=2}^{n}2(log_{2}{(i-1)}+1-1)=2\sum_{i=2}^{n}log_{2}{(i-1)}<2nlog_{2}{n}

总共时间=2nlog2n+4n<==>nlog2n

    public static void sift(long a[],int low,int high)
    {
    	int i=low;int j=2*i;//R[j] is the child of R[i]
    	long tmp=a[i];//需要筛选的值
    	while(j<=high)//保证孩子j没有超出数组
    	{
    		//j每次这时候指的都是左孩子
    		if(j<high&&a[j]<a[j+1])
    			j++;
    		if(tmp<a[j])
    		{
    			a[i]=a[j];
    			i=j;
    			j=2*i;
    		}
    		else break;
    	}
    	a[i]=tmp;
    }
	public static int text(long a[],int n)
    {
		long temp;
		for(int i=n/2;i>=1;i--)
			Helloworld.sift(a, i, n);
		for(int i=n;i>=2;i--)
		{
			temp=a[1];
			a[1]=a[i];
			a[i]=temp;
			Helloworld.sift(a, 1, i-1);
		}
        return 0;
    }

8-归并排序

一种稳定的排序方法,比较简单,主要思想就是把两个有序表合成一个,用一个辅助数组循环读取,再复制给原数组。

再写成递归,会一直递归到一个元素的有序表,即可完成排序。

	public static void text(long a[],int n)
    {
		long []temp=new long [100010];
		sort(a,1,n,temp);
    }
	public static void sort(long a[],int left,int right,long temp[])
	{
		if(left>=right)return ;
		int mid=(left+right)/2;
		sort(a,left,mid,temp);
		sort(a,mid+1,right,temp);
		merge(a,left,mid,right,temp);
	}
	public static void merge(long a[],int left,int mid,int right,long temp[])
	{
		if(left>=right)return;
		int i=left;
		int j=mid+1;
		int t=0;
		while(i<=mid&&j<=right)
		{
			if(a[i]<=a[j])
				temp[++t]=a[i++];
			else temp[++t]=a[j++];
		}
		while(i<=mid)temp[++t]=a[i++];
		while(j<=right)temp[++t]=a[j++];
		t=1;
		while(left<=right)
			a[left++]=temp[t++];
	}

基数排序想搁一段时间。

加上一个鸽一段时间的...https://blog.csdn.net/sunjinshengli/article/details/70738527

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/82691874
TEN