排序算法要點

第一篇: 堆排序


二叉堆滿足二個特性:
1).父結點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值。
2).每個結點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。


堆排序的三個要點
從小到大排序,要先建立最大堆。
以構建最大堆爲例

1.堆調整
以待排序節點開始,遍歷子節點,把兩個子節點值比較大的子節點向上移動。
兩個子節點都比該節點小,說明不用在調節了。注意,要保證這個步驟成立,本次堆調整時,子節點都是二叉堆。
當然了,葉子節點一定是二叉堆(因爲沒有子節點)。
還要注意一點是,一次調節交換可能會破壞子節點的有序性,所以每次調節都要調整到二叉樹葉節點位置(當然,也可以是兩個子節點都比該節點小時)。

2.構建堆
構建堆就是構建一個根節點位置開始的二叉堆。所以要先保證它的子節點也是二叉堆。
void MakeMinHeap(int a[], int n) 

 for (int i = n / 2; i > 0; i--) 
  MinHeapFixdown(a, i, n); 
}
注意,構建的二叉堆的數組元素還不是排好順序的,因爲不能保證左子樹和右子樹的順序。

3.二叉堆排序
二叉堆的根節點一定是最大的,將它換到數組末尾不再移動,將數據末尾的節點換到根節點,重新調整二叉堆。
重複這個過程,直到數據全部移動到二叉堆的後面。
for (int i = n; i > 1; i--) 

 swap(a[1], a[i]); 
 MinHeapFixdown(a, 1, i-1); 
}

 

第二篇、歸併排序

1. 合併相鄰子數組

需要注意的問題,當兩個數組長度不一樣時的情況。
事先分配臨時數組,將排序結果緩存,然後每次合併數組後,再保存回原來的數組。
也可以,將臨時數組和原數組每次排列交替做輸入數組和結果緩存數組(一趟完整歸併一次交換),避免copy。

2.歸併方式

遞歸方式:

void mergesort(int a[], int first, int last) 

    if (first < last) 
    { 
        int mid = (first + last) / 2; 
        mergesort(a, first, mid);    //左半邊排序
        mergesort(a, mid + 1, last); //右半邊排序 
        mergearray(a, first, mid, last); //左右兩個有序序列合併 
    } 
}

非遞歸方式:

1). 一趟歸併排序
將整個數組每seg長度分一段,每一段都進行排序,保證有序。

2). 歸併排序
有序子數組從下到上的順序進行合併。
分段長度seg由1逐漸增長到數組長度,排序完成。

源碼

int Merge(int data[],int res[], int low, int mid, int high)
{
	int i, j, k;   

	i = low;
	j = mid+1;
	k = low;

	while(i<=mid && j<=high) 
	{   
		if(data[i] <= data[j])   
			res[k++] = data[i++];   
		else   
			res[k++] = data[j++];   
	}   

	for(; i<=mid; i++)   
		res[k++] = data[i];   
	for(; j<=high; j++) 
		res[k++] = data[j];

	return k-low;
}

void mergeSort(int *data,int* res, int first, int last )   
{     
	if(first < last)     
	{   
		int mid = (first+last)/2;     
		mergeSort(data,res, first, mid);		//使左邊有序   
		mergeSort(data,res, mid+1, last);		//使右邊有序   
		int len = Merge(data,res, first, mid, last); //合併數組
		for ( int i = 0; i < len ; i++ )
		{
			data[first+i] = res[first+i];
		}
	}   
}   

void mergeSort(int *data, int len )   
{   
	int* temp = new int[len];
	mergeSort( data,temp, 0, len - 1 );
 	delete[] temp;
 	temp = NULL;
} 
//----------------------------------------------------------------------------------------

void MergePass(int data[], int res[], int seg, int size)
{
	int seg_start = 0;
	while(seg_start <= size - 2 * seg) //seg爲每段長度,將整個數組劃分
	{
		Merge(data, res, seg_start, seg_start + seg - 1, seg_start + seg * 2 - 1 );
		seg_start += 2 * seg;
	}
	//剩下大於一段小於兩段的數據
	if(seg_start + seg < size)
		Merge(data, res, seg_start, seg_start + seg - 1, size - 1 );
	else
		for(int j = seg_start; j < size; j++) //只剩下小於等於一段數據
			res[j] = data[j];
}

void MergeSort(int a[], int size)
{
	int* temp = new int[size];
	int seg = 1;
	while(seg < size)
	{
		MergePass(a, temp, seg, size);
		seg += seg;
		MergePass(temp, a, seg, size);
		seg += seg;
// 四路歸併了~
// 		MergePass(a, temp, seg, size);
// 		seg += seg;
// 		MergePass(temp, a, seg, size);
// 		seg += seg;
	}
	delete [] temp;
	temp = NULL;
}
//----------------------------------------------------------------------------------------
int main()       
{       
	int a[]={50,10,20,30,70,40,80,60};   
	//int a[] = {3, 5, 3, 6, 4, 7, 5, 7, 4};

	MergeSort(a, sizeof(a) / sizeof(*a));          

	for(int i=0; i<sizeof(a) / sizeof(*a); ++i)       
		cout<<a[i]<<" ";       
	cout<<endl;       
	
	mergeSort(a, sizeof(a) / sizeof(*a));       

	for(int i=0; i<sizeof(a) / sizeof(*a); ++i)       
		cout<<a[i]<<" ";       
	cout<<endl;

	system("pause");       
	return 0;       
} 


 

發佈了61 篇原創文章 · 獲贊 33 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章