排序演算法詳解
阿新 • • 發佈:2022-05-11
1. 直接插入排序(有序表的擴大)
void InsertSort(int *A,int n){
int i,j;
for(i=2;i<=n;i++){ //從第二個元素開始遍歷n-1次,插入到前面的有序陣列中
A[0]=A[i]; //儲存待插入元素
for(j=i-1;A[0]<A[j];--j)
A[j+1]=A[j]; //將大於待插入元素的元素往後移動一位,空出插入位置
A[j+1]=A[0]; //插入元素
}
}
折半插入排序
void InsertSort(int *A,int n){ int i,j,low,high,mid; for(i=2;i<=n;i++){ //從第二個元素開始遍歷n-1次,插入到前面的有序陣列中 A[0]=A[i]; //儲存待插入元素 low=1;high=i-1;//有序陣列的左右兩端指標 while(low<=high){ //折半查找出待插入位置 mid=(low+high)/2; if(A[mid]>A[0]) high=mid-1; else low=mid+1; } for(j=i-1;j>=high+1;--j) //跳出條件直接使用了插入位置high A[j+1]=A[j]; //將大於待插入元素的元素往後移動一位,空出插入位置 A[j+1]=A[0]; //插入元素 } }
希爾排序
void InsertSort(int *A,int n){ int i,j; for(dk=n/2;dk>=1;dk=dk/2) //步長每次縮小一半直至變為1 for(i=dk+1;i<=n;i++){ //從第1+dk個元素開始遍歷,插入到前面的有序非連續陣列中 if(A[i]<A[i-dk]){ //有序則跳過該次迴圈 A[0]=A[i]; //儲存待插入元素 for(j=i-dk;j>0&&A[0]<A[j];j-=dk) //變換的步長為dk A[j+dk]=A[j]; //將大於待插入元素的元素往後移動dk位,空出插入位置 A[j+dk]=A[0]; //插入元素 } } }
2. 氣泡排序(逐個冒出最值)
void BubbleSort(int *A,int n){ for(int i=0;i<n-1;i++){ //遍歷n-1趟 flag = false; //設定標誌位,當陣列有序即一趟沒發生交換時,跳出迴圈 for(int j=n-1;j>i;j--){ //從後往前交換 if(A[j-1]>A[j]){ //冒出最小值 swap(A[j-1],A[j]); flag=true; } } if(flag==flase) return; } }
3. 快速排序(樞軸遞迴分治)
void QuickSort(int *A,int low,int high){
if(low>=high) return;
int pivot_pos=Partition(A,low,high); //使樞軸右側大於左側並返回樞軸位置
QuickSort(A,low,pivot_pos-1); //遞迴樞軸左半邊
QuickSort(A,pivot_pos+1,high); //遞迴樞軸右半邊
}
int Partition(int *A,int low,int high){
int pivot= A[low]; //預設第一個元素為樞軸元素,並存儲起來
while(low<high){
while(low<high&&A[high]>=pivot) --high//移動右端指標至小於樞軸的元素
A[low]=A[high]; //將該元素換至左端
while(low<high&&A[low]<=pivot) ++low;//移動左端指標至大於樞軸的元素
A[high]=A[low]; //將該元素換至左端
}
A[low]=pivot;//樞軸元素放回樞軸位置
return low;//返回樞軸位置
}
4. 簡單選擇排序(選出最值)
void SelectSort(int *A,int n){
for(int i=0;i<n-1;i++){ //從前往後,進行n-1趟遍歷
min = i; //記錄這趟遍歷最小值位置
for(j=i+1;j<n;j++) //選出該趟遍歷最小元素
if(A[j]<A[min]) min=j; //選出最小值
if(min!=i) swap(A[i],A[min]); //如果最小元素不是待插入位置,則交換
}
}
5. 堆排序(利用堆的性質不斷調整和冒出最值)
void HeapSort(int *A,int len){
BuildMaxHeap(A,len); //建立大根堆
for(int i=len;i>1;i--){ //n-1趟交換和建堆過程
swap(A[i],A[1]); //輸出堆頂元素(和堆底元素交換)
HeadAdjust(A,1,i-1); //把剩餘i-1個元素調整成堆
}
}
void BuildMaxHeap(int *A,int len){
for(int i=len/2;i>0;i--) //從i=~n/2~1,反覆調整堆
HeadAdjust(A,i,len); //調整演算法把左右子樹皆為堆的樹調整成堆
}
void HeadAdjust(int *A,int k,int len){
//將元素k為根的子樹進行調整
A[0]=A[k]; //A[0]暫存子樹根節點
for(int i=2*k;i<=len;i*=2){ //該迴圈是為了將根節點值不斷往下送
if(i<len&&A[i]<A[i+1]) i++; //若右節點大,指標移動到右節點
if(A[0]>A[i]) break; //調整結束,即根節點大於兩子節點
else{ //否則繼續將根節點的值往下送
A[k]=A[i]; //根節點位置換成較大子節點的值
k=i; //記錄子節點指標作為新的根節點或終止節點
}
}
A[k]=A[0]; //迴圈結束終止節點賦往下送根節點值
}
6. 歸併排序(分治歸併有序子表)
void MergeSort(int *A,int low,int high){
if(low>=high) return;
int mid = (low+high)/2; //陣列分成兩部分
MergeSort(A,low,mid); //對左邊遞迴排序使其有序
MergeSort(A,mid+1,high); //對右邊遞迴排序使其有序
Merge(A,low,mid,high); //合併兩有序表
}
void Merge(int *A,int low,int mid,int high){
for(int k=low;k<=high;k++){
B[k]=A[k]; //複製出一個新的陣列作為比較
for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){ //從左往右,兩個指標對兩陣列逐個對比
if(B[i]<B[j]) A[k]=B[i++]; //將小的值賦回給A,並移動指標
else A[k]=B[j++];
}
while(i<=mid) A[k++]=B[i++]; //將沒複製完的複製過去
while(j<=high) A[k++]=B[j++]; //將沒複製完的複製過去
}
}