1. 程式人生 > >幾種基本排序算法總結

幾種基本排序算法總結

子序列 system aop 大於等於 != pri i++ index 元素移動

以下均采用從小到大排序:

1.選擇排序算法

個人覺得選擇排序算法是容易理解的排序算法,即從n個元素中選擇最小的一個元素與第一個元素交換,再將除第一個元素之外的n-1個元素找到最小的一個放在第二個位置,以此類推。

如:1,1,2,3,0

第一次排序:[0],1,2,3,1 //0最小,與第一個元素交換位置

//由這一步可知,原數組第一個元素與第二個元素都是1,第一次排序之後兩個元素的前後位置改變,可知選擇排序算法是不穩定的

第二次排序:[0,1],2,3,1 //經過比較後四個數的最小的是1,位置不變

第三次排序:[0,1,1],3,2 //經過比較後三個數的最小元素是1,1與第三個位置的元素即2交換位置

第四次排序:[0,1,1,2,3] //最後比較後兩個,交換

java實現:

public class XuanZe
{
	public static void main(String[] args)
	{
		int[] a={1,5,7,6,4,8,9,3,2,0};
		selectSort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void selectSort(int[] a)
	{
		int i,j,k,temp,c;
		for(i=0;i<a.length-1;i++)
		{
			temp=a[i];
			k=i;
			for(j=i+1;j<a.length;j++)
			{
				if(a[j]<temp)
				{
					temp=a[j];             //每次選擇最小的與前面的交換,這樣有可能改變原本的兩個相等的數的位置,
					                            //所以為不穩定的排序算法。如2 4 8 9 4,第一次排序時將會改變兩個4原本的前後位置
					k=j;
				}
			}
			if(k!=i)
			{
				c=a[i];
				a[i]=a[k];
				a[k]=c;
			}
		}
	}
}

選擇排序算法,無論之前是否有序,都要經過n-1趟排序,所以最好時間復雜度為O(n^2),最壞也是O(n^2),空間復雜度為:O(1)。適合n較小時的排序

2.冒泡排序算法

冒泡排序算法相對來說也很簡單,很多面試官愛考冒泡排序算法,不論是我之前聽一些學長考研時的面試問題,還是企業的面試考題都有冒泡排序算法的問題。冒泡排序算法大數逐漸往末尾走的算法。冒泡排序是不斷的通過相鄰兩個元素比較大小,不斷的交換位置實現的。

如:9 8 4 5 0

第一次排序 :8 4 5 0 [9] //在實現這個排序的過程中,9先和8比較,交換位置 得到8 9 4 5 0;9與4比較,交換位置得到8 4 9 5 0;9和5比較,交換位置,得到8 4 5 9 0;

//9與0比較,交換位置,得到8 4 5 0 9;相鄰兩個元素相等或者第i-1個元素小於第i個元素時,不交換,大於時交換位置由此也可知相等元素前後位置

//不會改變,冒泡排序算法為穩定的

第二次排序:4 5 0 [8 9]

第三次排序:4 0 [5 8 9]

第四次排序:[0 4 5 8 9]

java實現:

public class MaoPao
{
	public static void main(String[] args)
	{
		int[] a={0,4,8,9,7,6,5,3,2,1};
		bubbleSort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void bubbleSort(int[] a)
	{
		int i,j,k,temp;
		int len=a.length;
		for(i=0;i<len-1;i++)
		{
			k=len-1;
			for(j=0;j<k;j++)
			{
				if(a[j]>a[j+1])
				{
					temp=a[j];
					a[j]=a[j+1];
					a[j+1]=temp;
				}
			}
			k--;        //每次對數組的n個數經過冒泡排序之後最大的那個在最後面,
			             //只需要再對前n-1個元素進行排序
		}
	}
}

冒泡排序算法最好的情況下時間復雜度為O(n)(針對改進後的代碼,不對應我的代碼),最壞情況的時間復雜度也為O(n^2),平均時間復雜度為O(n^2),空間復雜度O(1)。適合於n較小時的排序。

3.插入排序算法

插入排序算法,假設第一個元素為有序序列,不斷的將第2,3,4......個數插入到有序序列中。

如:4 5 6 1 2

[4] 5 6 1 2 //首先將4作為有序序列;

第一次排序:[4 5] 6 1 2 //將5插入到4的有序序列,形成又一個有序隊列,以此下去

第二次排序:[4 5 6] 1 2 //因為插入的時候是將後面的元素插入到其前面的元素構成的有序序列當中,若是等於某個元素,即放在該元素的後面,所以不會 //改變相等的數前後位置關系

第三次排序:[1 4 5 6] 2 //排序之前的前後位置關系,是穩定的

第四次排序:[1 2 4 5 6]

java實現:

public class Cha
{
	public static void main(String[] args)
	{
		int[] a={1,5,8,9,3,0,2,7,4,6};
		insertSort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void insertSort(int[] a)
	{
		int i,j,k,temp;
		int len=a.length;
		for(i=1;i<len;i++)
		{
              temp=a[i];
			  if(i-1>=0)
			  {
				  while(i-1>=0&&a[i-1]>temp)      
				  {
					  a[i]=a[i-1];                      //把大的數放到後面,i--
					  i--;                                  //具有穩定性
				  }
			  }
			  a[i]=temp;
		}
	}
}

   最好時時間復雜度為O(n),最壞時間復雜度為O(n^2),平均時間復雜度為O(n^2),空間復雜度為O(1)。適合大部分是有序時。

4.希爾排序算法

希爾排序算法是對插入排序算法的改進。希爾排序相當於根據不同的步長將序列分為多個子序列,先對各個子序列使用插入排序算法排序,之後再對整個序列進行排序。步長的最後一個步長必須是1。

如:1 4 4 6 3 7 2 5 9 0

一共有10個數,步長應該為5 2 1

第一次排序:1 2 4 6 0 7 4 5 9 3 //此時步長為5,步長為5時,形成了5個子序列,分別是:1 7;4 2;4 5;6 9;3 0,用插入法對五個子序列排序,為:1 7; 2 4;4 5 ;

//6 9;0 3;合成之後為1 2 4 6 0 7 4 5 9 3

第二次排序:0 2 1 3 4 5 4 6 9 7 //此時步長為2,形成的子序列為:1 4 0 4 9 ;2 6 7 5 3 用插入法排序之後:0 1 4 4 9; 2 3 5 6 7即 0 2 1 3 4 5 4 6 9 7

第三次排序:0 1 2 3 4 4 5 6 7 9 //步長為1的插入排序算法;

//在第一次排序時,2與後面的那個4交換位置,改變了兩個4的前後順序,所以可知為不穩定排序算法

java實現:

public class XiEr
{
	public static void main(String[] args)
	{
		int[] a={1,5,2,7,8,4,9,6,3,0};
		shellSort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void shellSort(int[] a)
	{
		int len=a.length;
		int i,h,temp;
		for(h=len/2;h>0;h=h/2)
		{
			//步長為h的插入排序,因為步長會將序列分為不同的子序列,會打亂相同數的前後順序,所以為不穩定排序算法
			for(i=h;i<len;i++)
			{
                temp=a[i];
				if(i-h>=0)
				{
					while(i-h>=0&&a[i-h]>temp)
					{
						a[i]=a[i-h];
						i=i-h;
					}
				}
				a[i]=temp;
			}
		}
	}
}

最好的時間復雜度為O(n),平均時間復雜度為O(nlogn),空間復雜度O(1).

5.快速排序算法

快速排序算法是一個遞歸的排序算法,首先將第一個元素i作為分界點,後面大於i的元素移動到i後面,小於i的元素移動到i前面。在將i前面的元素作為一個序列,在i後面的元素作為一個序列。在將這兩個序列的第一個元素作為分界點重復這個操作。

如: 4 7 5 8 2 1 3

第一次排序: [2 1 3] 4 [7 5 8] //首先將4作為分界點,大於等於4的移動到4之後,小於4的移動到4之前,將2 1 3作為一個序列, 7 5 8作為一個序列

第二次排序: 1 2 3 4 5 7 8 //將2作為分界點,大於2的移動到2之後,小於2的移動到2之前,得到 1 2 3,同理得到5 7 8

java實現:

public class Kuai
{
	public static void main(String[] args)
	{
		int[] a={0,5,7,8,4,6,9,3,2,1};
		int len=a.length;
		quickSort(a);
		for(int i=0;i<len;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void quickSort(int[] a)
	{
		quick(a,0,a.length-1);
	}
	public static void quick(int[] a,int p,int q)
	{
		int index;
		int i=p;
		int j=q;
		if(p>=q)
		{
			return;
		}
		index=a[i];
		while(i<j)
		{
			while(i<j&&a[j]>=index)   //由於從兩側開始排序,不穩定
			{
				j--;
			}
			if(i<j)
			{
				a[i++]=a[j];
			}
			while(i<j&&a[i]<index)
			{
				i++;
			}
			if(i<j)
			{
				a[j--]=a[i];
			}
		}
		a[i]=index;
		quick(a,p,i-1);
		quick(a,i+1,q);
	}
}

  最好時間復雜度為O(nlogn),最壞時間復雜度為O(n^2),平均時間復雜度O(nlogn),空間復雜度為O(nlogn),適合n較大的情況

6.歸並排序算法

歸並排序算法即先將數據序列劃分為越來越小的半子表,再對半子表排序,最後再用遞歸的方法將半子表合並成越來越大的有序序列

如:7 8 4 5 2 1 3

先成為[7 8 4 5]和[2 1 3]兩個序列,再次劃分成為[7 8] ,[4 5],[2 1],[3]四個序列,再次劃分為 [7] ,[8],[4],[5],[2],[1],[3],歸並時進行排序

第一次歸並為[7 8],[4 5],[1 2],[3]

第二次歸並為[4 5 7 8],[1 2 3]

第三次歸並為[1 2 3 4 5 6 7 8] //歸並排序時並不會改變相同數的前後順序,穩定的排序算法

java實現:

public class GuiBing
{
	public static void main(String[] args)
	{
		int[] a={0,5,7,8,4,6,9,3,2,1};
		int len=a.length;
		guiSort(a,0,len-1);
		for(int i=0;i<len;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
	public static void guiSort(int[] a,int p,int q) 
     //歸並因為是為了拆開然後排序,並不會改變相同數的位置,穩定排序
	{
		int r;
		if(p<q)         
		{
			r=(p+q)/2;
			guiSort(a,p,r);
			guiSort(a,r+1,q);
			gui(a,p,r,q);
		}
	}
	public static void gui(int[] a,int p,int r,int q)
	{
	     int i,j,k,n1,n2;        
		 int[] L;
		 int[] R;
		 n1=r-p+1;
		 n2=q-r;
		 L=new int[n1];
         R=new int[n2];
		 for(i=0,k=p;i<n1;i++,k++)
		 {
			 L[i]=a[k];
		 }
		 for(i=0,k=r+1;i<n2;i++,k++)
		{
			 R[i]=a[k];
		 }
		 for(i=0,j=0,k=p;i<n1&&j<n2;k++)
		{
			 if(L[i]<R[j])
			{
				 a[k]=L[i++];
			 }
			 else
			{
				 a[k]=R[j++];
			 }
		 }
		 if(i<n1)
		{
			 for(j=i;j<n1;j++)
			{
				 a[k++]=L[j];
			 }
		 }
		 if(j<n2)
		{
			 for(i=j;i<n2;i++)
			{
				 a[k++]=R[i];
			 }
		 }
	}
}

  最好的時間復雜度為O(nlogn),最壞的時間復雜度為O(nlogn),平均時間復雜度為O(nlogn),空間復雜度O(n),n大時比較好。

7.堆排序算法

堆是一種特殊的樹形數據結構。堆排序利用的是一樹形選擇結構。堆分為大頂堆和小頂堆,大頂堆即每一個節點都比左子樹和右子樹大,小頂堆即每一個節點都比左子樹和右子樹大。

所以在使用堆排序算法時,首先是先構造堆,然後交換堆頂元素和最後一個元素的位置。

堆排序算法因為過於復雜,我不太會弄,就不詳解,參照http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621,博主講的很清晰。

java實現:

public class Dui
{
	public static void main(String[] args)
	{
		int[] a={0,7,8,6,5,4,3,2,9,10,1};
		int len=a.length;
		MaxHeap(a);
		for(int i=0;i<len;i++)
		{
			System.out.print(a[i]+"  ");
		}
	}
    public static void MaxHeap(int[] a)
	{
		int len=a.length;
		int i,temp;
		for(i=len/2-1;i>=0;i--)
		{
			adjustMaxHeap(a,i,len-1);
		}
		for(i=len-1;i>=0;i--)
		{
             temp=a[0];
			 a[0]=a[i];
			 a[i]=temp;
			 adjustMaxHeap(a,0,i-1);
		}
	}
	public static void adjustMaxHeap(int[] a,int pos,int len)
	{
		int child,temp;
		for(temp=a[pos];2*pos+1<=len;pos=child)
		{
			child=2*pos+1;
			if(child<len&&a[child]<a[child+1])   //由於child可以等於len,此處child<len即child+1<=len;
			{
				child++;                                   //不穩定
			}
			if(a[child]>temp)
			{
				a[pos]=a[child];
			}
			else
			{
				break;
			}
		}
		a[pos]=temp;
	}
}

最好的時間復雜度為O(nlogn),最壞的時間復雜度為O(nlogn),平均時間復雜度為O(nlogn),空間復雜度為O(1),適合n較大的情況。

幾種基本排序算法總結