排序(C語言實現)
阿新 • • 發佈:2018-09-08
內部排序 利用 int 分治 arr 個數 size quic 外部排序
讀數據結構與算法分析
插入排序
核心:利用的是從位置0到位置P都是已排序的
所以從位置1開始排序,如果當前位置不對,則和前面元素反復交換重新排序
實現
void InsertionSort(ElementType A[], int N) { int i,P; ElementType Tmp ; for(P = 1;P < N;P++) { Tmp = A[P] ; for(i = P;i > 0 && A[i-1] > Tmp;i--) A[i] = A[i-1] ; A[i] = Tmp ; } }
希爾排序
使用hk增量序列進行一趟排序後,對每個i都有
A[i] \leq A[i+hk]
重要性質:一個hk排序的文件在之後的排序中將保持hk排序性
實現
- ht = [N / 2]
- hk = [hk+1 / 2]
void ShellSort(ElmentType A[], int N) { ElementType Tmp ; int i,j,Increment ; for(Increment = N/2;Increment > 0;Increment /= 2) for(i = Increment;i < N;i++) { Tmp = A[i] ; for(j = i;j <= Increment;j -= Increment) if(Tmp < A[j-Increment]) A[j] = A[j-Increment] ; else break ; A[j] = Tmp ; } }
堆排序
基於原有的二叉堆
建立二叉堆,執行DeleteMax操作,儲存至數組(節省空間可以倒序儲存在當前數組)
實現
#define LeftChild(i) (2 * i + 1) ; void Percdown(ElementType A[],int i,int N) { int Child ,i; ElementType Tmp ; for(Tmp = A[i]; LeftChild(i) < N-1;i = Child) { Child = LeftChild(i) ; if(Tmp < A[Child]) A[i] = A[Chile] ; else break ; } A[i] = Tmp ; } void HeapSore(ElementType A[],int N) { int i ; for(i = N/2 ;i >= 0;i--) Percdown(A,i,N) ; //建立二叉堆 for(i = N-1; i > 0; i--) { Swap(&A[0],&A[i]) ; Percdown(A,0,i) ; } }
歸並排序
基本思想是合並兩個已排序的表
實現
遞歸合並
void Msort(ElementType A[],ElementeType TmpArray[],int Left,int Right)
{
int Center ;
if(Left < Right)
{
Center = (Left + Right) /2 ;
Msort(A,TmpArray,Left,Right) ;
Msort(A,TmpArray,Center + 1,Right) ;
Merge(A,TmpArray,Left,Center + 1,Right) ;
}
}
驅動程序
void Mergesort(ElementType A[],int N)
{
ElementType *TmpArray ;
TmpArray = malloc(N * sizeof(ElementType)) ;
if(TmpArray != NULL)
{
Msort(A,TmpArray,0,N-1) ;
free(TmpArray) ;
}
else
FatalError("內存不足") ;
}
合並函數
void Merge(ElementType A[],ElementType TmpArray[],int Lpos,int Rpos,int RightEnd)
{
int i,LeftEnd,NumElements,TmpPos ;
LeftEnd = Rpos - 1;
TmpPos = Lpos ;
NumElement = RightEnd - Lpos + 1 ;
while(Lpos <= LeftEnd && Rpos <= RightEnd)
if(A[Lpos] <= A[Rpos])
TmpArray[TmpPos++] = A[Lpos++] ;
else
TmpArray[TmpPos++] = A[Rpos++] ;
while(Lpos <= LeftEnd)
TmpArray[TmpPos++] = A[Lpos++] ;
while(Rpos <= RightEnd)
TmpArray[TmpPos++] = A[Rpos++]
for(i = 0;i < NumElement ;i++,RightEnd--)
A[RightEnd] = TmpArray[RightEnd] ;
}
快速排序
和歸並排序一樣都是分治遞歸算法,在小數組上效率並沒有插入排序好
- 如果S中元素個數是0或1,則返回
- 取S中任一元素v,稱為樞紐元
- 將S剩余的其它元素,分為兩個不相交的集合
- 返回quicksort(S1),繼續選擇v,繼續quicksort(S2) ;
實現
選取樞紐元
三數中值分割方法
ElementType Median3(ElementType A[],int Left,int Right)
{
int Center = (Left + Right) / 2 ;
if(A[Left] > A[Center])
Swap(&A[Left],&A[Center]) ;
if(A[Left] > A[Right])
Swap(&A[Left],&A[Right]) ;
if(A[Center] > A[Right])
Swap(&A[Center],&A[Right]) ;
Swap(&A[Center],&A[Right - 1]) ;
return A[Right - 1] ;
}
主函數
#define Cutoff(3) ;
void Qsort(ElementType A[],int Left,int Right)
{
int i,j ;
ElementType Pivot ;
if(Left + Cutoff <= Right)
{
Pivot = Midian3(A,Left,Right)
i = Left ; j = Right ;
for(;;)
{
While(A[++i] < Privot){}
While(A[--j] > Privot){}
if(i < j)
Swap(&A[i],&A[j]) ;
else
break ;
}
Swap(&A[i],&A[Right-1]) ;
Qsort(A,Left,i-1) ;
Qsort(A,i+1,Right) ;
}
else
InsertionSort(A + Left,Right - Left + 1) ;
}
驅動函數
void QuickSort(ElementType A[],int N)
{
Qsort(A,0,N-1) ;
}
總結
- 對於一般的內部排序,選用的方法一般是插入排序、希爾排序和快速排序,根據輸入來選擇
高度優化的快速排序在對於很少的輸入也可能和希爾排序一樣快
對於快速排序,選取樞紐元十分關鍵
- 堆排序比希爾排序要滿
- 插入排序一般用於較小的或接近排好序的輸入
歸並排序在主存排序中不如快速排序那麽好,但是合並時外部排序的中心思想
排序(C語言實現)