1. 程式人生 > >《資料結構》09-排序1 排序

《資料結構》09-排序1 排序

題目

給定N個(長整型範圍內的)整數,要求輸出從小到大排序後的結果。

本題旨在測試各種不同的排序演算法在各種資料情況下的表現。各組測試資料特點如下:

  • 資料1:只有1個元素;
  • 資料2:11個不相同的整數,測試基本正確性;
  • 資料3:10​ 3 ^3 個隨機整數;
  • 資料4:10​
    4 ^4
    個隨機整數;
  • 資料5:10​ 5 ^5 個隨機整數;
  • 資料6:10​
    5 ^5
    個順序整數;
  • 資料7:10​ 5 ^5 個逆序整數;
  • 資料8:10​
    5 ^5
    個基本有序的整數;
  • 資料9:10​ 5 ^5 個隨機正整數,每個數字不超過1000。

輸入格式:
輸入第一行給出正整數N(≤10​ 5 ^5 ​​ ),隨後一行給出N個(長整型範圍內的)整數,其間以空格分隔。

輸出格式:
在一行中輸出從小到大排序後的結果,數字間以1個空格分隔,行末不得有多餘空格。

輸入樣例:

11
4 981 10 -17 0 -20 29 50 8 43 -5

輸出樣例:

-20 -17 -5 0 4 8 10 29 43 50 981

分析

基本就是各種排序演算法的測試了

  • 氣泡排序
  • 插入排序
  • 原始希爾排序
  • Hibbard增量序列希爾排序
  • Sedgewick增量序列雜湊排序
  • 堆排序
  • STL實現堆排序
  • 遞迴歸併排序
  • 非遞迴歸併排序
  • 快速排序
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std; 

// 氣泡排序 
void Bubble_sort(long A[],int N){
	for(int i=0;i<N-1;i++){  // N-1次冒泡
		bool flag = false;  // 驗證是否互動過 
		for(int j=0;j<N-i-1;j++){
			if(A[j+1] < A[j]){
				flag = true; 
				swap(A[j],A[j+1]);
			}
		} 
		// 已經有序 
		if(!flag)  
			break; 
	} 
} 

// 插入排序
void Insertion_sort(long A[],int N){
	for(int i=1;i<N;i++){  // 第一個已經成序 
		long tmp = A[i];
		int j=i;
		for(;tmp<A[j-1] && j>0;j--)
			A[j] = A[j-1];
		A[j] = tmp;
	}
}

// 原始希爾排序 
void shell_sort(long A[],int N){
	for(int D=N/2;D>0;D/=2){
		for(int p=D;p<N;p++){
			long tmp = A[p];
			int k=p;
			for(;k>=D && tmp<A[k-D] ;k-=D) // j>=D 在前,因為也許 A[j-D]已經越界 
				A[k] = A[k-D];
			A[k] = tmp;
		}
	}
} 

// Hibbard增量序列希爾排序 
void Hibbard_shell_sort(long A[],int N){
	int add[]={32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0};
	int i=0;
	for(int D=add[i];D>0;D=add[++i]){
		for(int p=D;p<N;p++){
			long tmp = A[p];
			int k=p;
			for(;k>=D && tmp<A[k-D] ;k-=D) // j>=D 在前,因為也許 A[j-D]已經越界 
				A[k] = A[k-D];
			A[k] = tmp;
		}
	}
} 
// Sedgewick增量序列雜湊排序 
void Sedgewick_shell_sort(long A[],int N){
	int add[]= {587521,260609,146305,64769,36289,16001,8929,3905,2161,929,505,209,109,41,19,5,1,0};
	int i=0;
	for(int D=add[i];D>0;D=add[++i]){
		for(int p=D;p<N;p++){
			long tmp = A[p];
			int k = p;
			for(;k>=D && tmp<A[k-D];k-=D)
				A[k] = A[k-D];
			A[k] = tmp;
		}
	} 
}

/***************堆排序開始***************/

// 調整成最大堆 
void PrecDown(long A[],int i,int N){
	int parent,child;
	long tmp = A[i];
	// 從 0 開始存,所以關係有變化 
	for(parent = i;parent*2+1<N;parent = child){
		child = parent*2+1;
		if((child!=N-1) && (A[child] < A[child+1]))
			child++;
		if(A[child] <= tmp)
			break;
		else
			A[parent] = A[child];
	}
	A[parent] = tmp;
}

// 堆排序 
void Heap_sort(long A[],int N){
	// 先調整成最大堆 
	for(int i=N/2;i>=0;i--)
		PrecDown(A,i,N);
	for(int i=N-1;i>0;i--){
		swap(A[0],A[i]); // 每次把當前最大堆根元素選擇出來 
		PrecDown(A,0,i);  // 再次調整最大堆 
	}
} 

/***************堆排序結束***************/

/***************stl堆排序開始***************/
priority_queue<long,vector<long>,less<long> > q; // 定義一個最大堆 

void STL_Heap_sort(long A[],int N){
	// 資料讀入最大堆 
	for(int i=0;i<N;i++)
		q.push(A[i]);
	// 依次出隊 
	for(int i=N-1;i>=0;i--){
		A[i] = q.top();
		q.pop();
	}
} 
/***************stl堆排序結束***************/

/***************遞迴歸併排序開始***************/
/*
// 歸併實現 
void Merge(long A[],long tmpA[],int L,int R,int RightEnd){
	// L = 左邊元素開始位置 ,R = 右邊元素開始位置 ,RightEnd = 右邊結束終點位置
	int NumSize = RightEnd-L+1; // 元素個數
	int LeftEnd = R-1;  // 左邊元素終點位置
	int tmp = L;  // tmp 陣列開始位置 
	while( L <= LeftEnd && R <= RightEnd ){
		if(A[L] <= A[R]) // 從小到大排序,選小的 
			tmpA[tmp++] = A[L++];
		else
			tmpA[tmp++] = A[R++];
	} 
	// 也許左沒走完 
	while( L <= LeftEnd )
		tmpA[tmp++] = A[L++];
	// 也許右邊沒走完 
	while( R <= RightEnd)
		tmpA[tmp++] = A[R++];
	// 再導回 A ,tmp此時已經越界,所以要先減再用 
	for(int i=0;i<NumSize;i++)
		A[RightEnd--] = tmpA[--tmp];
}

// 分治 
void Msort(long A[],long tmpA[],int L,int RightEnd){
	if(L < RightEnd){
		int center = ( L + RightEnd )/2;
		Msort(A,tmpA,L,center);
		Msort(A,tmpA,center+1,RightEnd);
		Merge(A,tmpA,L,center+1,RightEnd);
	}
}

void Merge_sort(long A[],int N){
	long tmpA[N];
	Msort(A,tmpA,0,N-1);
}
*/
/***************遞迴歸併排序結束***************/

/***************非遞迴歸併排序開始***************/
// 歸併實現 ,最後不把元素倒回A 
void Merge1(long A[],long tmpA[],int L,int R,int RightEnd){
	// L = 左邊元素開始位置 ,R = 右邊元素開始位置 ,RightEnd = 右邊結束終點位置
	int NumSize = RightEnd-L+1; // 元素個數
	int LeftEnd = R-1;  // 左邊元素終點位置
	int tmp = L;  // tmp 陣列開始位置 
	while( L <= LeftEnd && R <= RightEnd ){
		if(A[L] <= A[R]) // 從小到大排序,選小的 
			tmpA[tmp++] = A[L++];
		else
			tmpA[tmp++] = A[R++];
	} 
	// 也許左沒走完 
	while( L <= LeftEnd )
		tmpA[tmp++] = A[L++];
	// 也許右邊沒走完 
	while( R <= RightEnd)
		tmpA[tmp++] = A[R++];
}

// 一趟歸併 
void Merge_pass(long A[],long tmpA[],int N,int length){
	int i;
	// 每 2*length 一個單元歸併 
	for(i=0;i<N-2*length;i+=2*length)
		Merge1(A,tmpA,i,i+length,i+2*length-1);
	// 處理剩餘不足一個單元的值 
	if(i+length < N)  // 剩下兩個子列,左邊夠,右邊不夠 
		Merge1(A,tmpA,i,i+length,N-1);
	else    //  剩下一個子列,左邊都不夠 
		for(int j=i;j<N;j++)
			tmpA[j] = A[j];
}


void Merge_sort(long A[],int N){
	int length = 1;
	long tmpA[N];
	// 保證每次兩趟歸併,最終結果一定存在 A中 
	while(length < N){
		Merge_pass(A,tmpA,N,length);
		length *=2;
		Merge_pass(tmpA,A,N,length);
		length *=2;
	}
}

/***************非遞迴歸併排序結束***************/

/*********************快速排序開始*******************************************/ 
// 選主元 
long getPivot(long A[],int L,int R){
	int center = (L+R)/2;
	if(A[R] < A[center])
		swap(A[R],A[center]);
	if(A[R] < A[L])
		swap(A[R],A[L]);
	if(A[center] < A[L])
		swap(A[center],A[L]);
	swap(A[center],A[R-1]);
	return A[R-1];
}

void QucikSort(long A[],int Left,int Right){
	int cutoff = 50;
	if( cutoff <= Right - Left ){  // 如果規模大用快排 
		int pivot = getPivot(A,Left,Right);
		int i = Left;      
		int j = Right-1; 
		for(;;){
			// 從前往後找比 pivot 小的 
			while(A[++i] < pivot);
			// 從後往前找比 pivot 大的 
			while(A[--j] > pivot);
			if(j <= i)
				break;
			swap(A[i],A[j]);
		}
		// 將主元放在合適位置 
		swap(A[i],A[Right-1]);
		QucikSort(A,Left,i-1);
		QucikSort(A,i+1,Right);
	}else   // 否則用插入排序 
		Insertion_sort(A+Left,Right-Left+1);
}

void Quick_sort(long A[],int N){
	QucikSort(A,0,N-1);
}

/*********************快速排序結束**********************************/ 

int main(){
	int N;
	cin>>N;
	long A[N];
	for(int i=0;i<N;i++)
		cin>>A[i];
	Merge_sort(A,N);
	for(int i=0;i<N;i++){
		if(i)
			cout<<" ";
		cout<<A[i];
	}
	return 0;
}