數據結構總結(排序技術)

  數據結構也到達了終點,最後的考試也步步緊逼。最後的時間裏,有必要合理分配空閒時間,制定好學習計劃,在考前充分複習,儘自己最大努力。這最後一章,介紹了與查找技術不同的排序技術,但同樣的都是一些優秀的思想方法,思維上有些難度,不去深入理解,很容易出現細節方面問題。

一,排序的基本概念

  1,穩定性的概念:同一數據重複出現,相對位置不發生變化則稱穩定。

  2,時間性能取決於比較次數+移動次數。

  3,各類算法存儲結構,順序存儲數組下標從1開始,0下標做輔助空間。

二,插入類的排序

  1,直接插入排序,穩定

  在插第i個記錄時前i-1個已排好序

for (i=2; i<=n; i++)   { 
       r[0]=r[i]; j=i-1;
       while (r[0]<r[j])       {  //r[0]做監視哨
           r[j+1]=r[j];	
	 j=j-1;	
        }
       r[j+1]=r[0];	
    }

  2,希爾排序(縮小增量排序),不穩定

將整個待排序記錄分割成若干個子序列,在子序列內分別進行直接插入排序,待整個序列中的記錄基本有序時,對全體記錄進行直接插入排序。初始增量d=n/2(d個子序列同步進行)

  for (d=n/2; d>=1; d=d/2){
     for (i=d+1; i<=n; i++) {
	     r[0]=r[i];           
	     j=i-d;                
	     while (j>0 && r[0]<r[j])
	     { 
          	r[j+d]=r[j]; //記錄後移d個位置
	          j=j-d;          //比較統一子序列的前一個記錄
	      }
	      r[j+d]=r[0]; 
	}
  }

三,交換排序

  1,相鄰比序(冒泡),穩定

  改進原版冒泡提高性能,減少比較次數,記錄最後一次交換位置,下次交換到此結束,無交換時退出。

 exchange=n; 	
    while (exchange) 
    {
        bound=exchange; 
        exchange=0;  
        for (j=1; j<bound; j++)
            if (r[j]>r[j+1]) {
                r[j]←→r[j+1];
	      exchange=j; //記錄最後交換的位置
            }
     }

  2,快速排序

  首先選一個值(即比較的基準),通過一趟排序將待排序記錄分割成獨立的兩部分,前一部分記錄的關鍵碼均小於或等於軸值,後一部分記錄的關鍵碼均大於或等於軸值,然後分別對這兩部分重複上述方法,直到整個序列有序。可用二叉樹描述,深度表示遞歸次數。


void QuickSort (int  r[ ], int first, int end )
{
    if (first < end) {	
    pivotpos = Partition (r, first, end );  //一次劃分  
   //對前一個子序列進行快速排序
    QuickSort (r, first, pivotpos-1);      
   //對後一個子序列進行快速排序
   QuickSort (r, pivotpos+1, end ); 
}
}
int Partition(int r[ ], int first, int end)
{	
    i=first; j=end;         //初始化
    r[0]=r[i];
     while (i<j)	
    {  
      while (i<j && r[0]<= r[j]) j--;  //右側掃描
       if (i<j) { 
          r[i]=r[j];   i++;  //將較小記錄交換到前面
       }
       while (i<j && r[i]<= r[0]) i++;  //左側掃描
       if (i<j) {
          r[j]=r[i];   j--;  //將較大記錄交換到後面
       }
    }
    r[i]=r[0];
    retutn i;    //i爲軸值記錄的最終位置
}

四,選擇排序,無最好最壞情況之分。

   1,簡單選擇排序,不穩定,時間複雜度永遠是n方

基本思想:i 趟在n-i+1i=1,2,…,n-1個記錄中選取關鍵碼最小的記錄作爲有序序列中的第i個記錄。

    for ( i=1; i<n; i++) 
    {  
        index=i; 		//index記錄有序數組的最後位置
        for (j=i+1; j<=n; j++) 
           if  (r[j]<r[index])  index=j;
        if (index!=i)   r[i]<==>r[index]; 	 
    }

2,堆排序,不穩定

堆是具有下列性質的完全二叉樹:每個結點的值都小於或等於其左右孩子結點的值(稱爲小根堆),或每個結點的值都大於或等於其左右孩子結點的值(稱爲大根堆)。

要得到升序的序列則要構造大根堆

#include<bits/stdc++.h>
using namespace std;
int judge(int a[],int i,int j)
{
    int k=i;
    int l=2*k;
    int t=a[k];
    while(l<=j)
    {
        if(l<j&&a[l]<a[l+1])
            l++;
        if(t>a[l]) break;
        else
        {
            a[k]=a[l];
            k=l;
            l=2*k;
        }
    }
    a[k]=t;
}
void h(int a[],int n){
for(int j=n/2;j>=1;j--)
    judge(a,j,n);
    for(int i=1;i<n;i++)
    {
        //swap(a[1],a[n-i+1]);
        int f=a[1];
        a[1]=a[n-i+1];
        a[n-i+1]=f;
        judge(a,1,n-i);
    }
}
int main()
{
    int n,a[9999];
    cin>>n;

    for(int i=1;i<=n;i++)
    cin>>a[i];
    h(a,n);

     for(int i=1;i<=n;i++)
    cout<<a[i]<<" ";
    }

 

 

五,歸併排序(分治的思想)

將n個待排序的記錄的序列看成n個長度爲一的有序序列。

1,二路歸併排序

歸併排序的主要操作是歸併,其主要思想是:將若干有序序列逐步歸併,最終得到一個有序序列 無法原地進行引入相同大小的數組存中間結果

#include<bits/stdc++.h>
using namespace std;
void judge(int a[],int b[],int s,int m,int t)
{
    int i=s;
    int j=m+1;
    int k=s;
    while(i<=m&&j<=t)
    {
        if(a[i]<=a[j]) b[k++]=a[i++];
        else
            b[k++]=a[j++];
    }
    if(i<=m)
        while(i<=m)
        {
            b[k++]=a[i++];
        }
    else
        while(j<=t)
            b[k++]=a[j++];
}
void mp(int a[],int b[],int n,int h)
{
    int i=1;
    while(i<=n-2*h+1)
    {
        judge(a,b,i,i+h-1,i+2*h-1);
        i+=2*h;
    }
    if(i<n-h+1) judge(a,b,i,i+h-1,n);
    else for(int k=i; k<=n; k++)
            b[k]=a[k];
}
void msort(int a[],int b[],int n)
{
    int h=1;
    while(h<n)
    {
        mp(a,b,n,h);
        h=2*h;
        mp(b,a,n,h);
        h=2*h;
    }
}
int main()
{
    int n,a[9999],b[9999];
    cin>>n;

    for(int i=1; i<=n; i++)
        cin>>a[i];
        msort(a,b,n);
    for(int i=1; i<=n; i++)
        cout<<a[i]<<" ";
    cout<<endl;
    for(int i=1; i<=n; i++)
        cout<<b[i]<<" ";

}

 

 

 

 

六,分配排序

基於分配和收集,不經過比較

  1,桶式排序,穩定

int  main(){
	Node *s,*first;	head *list;
	int m;cin>>m;
	list=new head[m];
	for (int i=0;i<=m;i++){
		list[i].first=NULL;	list[i].rear=NULL;}
	int n;
	cin>>n;
	first=NULL;
	for( i=0;i<n;i++)
	{	s=new Node;	cin>>s->data;	s->next=first;	first=s;	}
	distribute(first,n,list);
	collect(list,first,m);
	Node *p=first;
	while(p){
		cout<<p->data<<"\t";	p=p->next;	}
	cout<<endl;
	return 0;
}

  2,基數排序,穩定

低位優先,尾插法

void distribute(Node *first, int n, head *list,int d){
	Node *p,*q;	p=first;	int data, s,t;
	while(p)	{
		data=p->data;
		s=pow(10,d);t=s/10;data=data%s;data=data/t;
		q=p->next;
		if(	list[data].first)
		{list[data].rear->next=p;	list[data].rear=p;}
		else
			list[data].first=list[data].rear=p;
		list[data].rear->next=NULL;
		p=q;
	}
	
}
void collect( head *list, Node *&first,int m){
	int i=0,j;
	while(list[i].first==NULL) 	i++;
	if(i>m) return;
	first=list[i].first;
	while(i<=m)	{
		j=i+1;
		while(list[j].first==NULL)	j++;
		if(j>m) return;
		list[i].rear->next=list[j].first;
		i=j;
	}
}






cin>>d;
	for(i=1;i<=d;i++) //處理每一“位”(個位、十位...)
	{
		distribute(first,n,list ,i);
		collect(list,first,m);
		for (int i=0;i<=m;i++)
		{
			list[i].first=NULL;	
			list[i].rear=NULL;	
		}
	}

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章