排序演算法---之交換排序(氣泡排序&快速排序-左右指標法,挖坑法,前後指標法)
排序演算法----交換排序(氣泡排序&快速排序)
一、排序演算法分為:
1.插入排序(直接插入排序&希爾排序)
2.選擇排序(直接選擇排序&堆排序)
3.交換排序(氣泡排序&快速排序)
4.歸併排序
----快速排序總共有三種方法:(1).左右指標法(2).挖坑法(3).前後指標法
二、幾種排序的效能比較
排序方法的比較 |
||||||
類別 |
排序方法 |
時間複雜度 |
空間複雜度 |
穩定性 |
||
平均情況 |
最好情況 |
最壞情況 |
輔助儲存 |
|||
插入排序 |
直接插入 |
O(n2) |
O(n) |
O(n2) |
O(1) |
穩定 |
希爾排序 |
O(n1.3) |
O(n) |
O(n2) |
O(1) |
不穩定 |
|
選擇排序 |
直接選擇 |
O(n2) |
O(n2) |
O(n2) |
O(1) |
不穩定 |
堆排序 |
O(nlog2n) |
O(nlog2n) |
O(nlog2n) |
O(1) |
不穩定 |
|
交換排序 |
氣泡排序 |
O(n2) |
O(n) |
O(n2) |
O(1) |
穩定 |
快速排序 |
O(nlog2n) |
O(nlog2n) |
O(n2) |
O(nlog2n) |
不穩定 |
|
歸併排序 |
O(nlog2n) |
O(nlog2n) |
O(nlog2n) |
O(n) |
穩定 |
|
基數排序 |
O(d(r+n)) |
O(d(rd+n)) |
O(d(r+n)) |
O(rd+n) |
穩定 |
|
注:基數排序中,n代表關鍵字的個數,d代表長度,r代表關鍵字的基數 |
三、氣泡排序
1.程式碼
2.時間複雜度://氣泡排序 void BubbleSort(int* a,size_t n) { assert(a); int end = n; while(end>0) { for(int i=0;i<end;++i) { if(a[i-1]>a[i]) { swap(a[i-1],a[i]); } } --end; } } //列印函式 void PrintArray(int* a,size_t n) { for(size_t i=0;i<n;++i) { cout<<a[i]<<" "; } cout<<endl; } //測試程式碼 void BubbleSortTest() { int a[]={2,5,4,0,9,3,6,8,7,1}; PrintArray(a,sizeof(a)/sizeof(a[0])); BubbleSort(a,sizeof(a)/sizeof(a[0])); PrintArray(a,sizeof(a)/sizeof(a[0])); }
最好情況:O(n)
最壞情況:O(n^2)
平均情況:O(n^2)
空間複雜度:O(1)
3.穩定性:穩定
四、快速排序
方法一:左右指標法
演算法程式碼:
//方法一:左右指標法
int PartSort1(int* a,int left,int right)
{
int key = a[right];
int begin = left;//左右指標,下標
int end = right;
while(begin<end)
{
while(begin<end && a[begin]<=key)//從左邊找比key大的值
{
++begin;
}
while(begin<end && a[end]>=key)//從右邊找比key小的值
{
--end;
}
if(begin<end)
{
swap(a[begin],a[end]);
}
swap(a[begin],a[right]);
}
return a[begin];
}
void QuickSort1(int* a,int left,int right)
{
assert(a);
if(left<right)
{
int div = PartSort1(a,left,right);
QuickSort1(a,left,div-1);
QuickSort1(a,div+1,right);
}
}
//列印函式
void PrintArray(int* a,size_t n)
{
for(size_t i=0;i<n;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
int a[]={2,5,4,0,9,3,6,8,7,1};
PrintArray(a,sizeof(a)/sizeof(a[0]));
QuickSort1(a,0,(sizeof(a)/sizeof(a[0]))-1);
PrintArray(a,sizeof(a)/sizeof(a[0]));
}
方法二:挖坑法
演算法程式碼:
//方法二:挖坑
int PartSort2(int* a,int left,int right)
{
int key = a[right];
while(left<right)
{
while(left<right && a[left]<=key)
{
++left;
}
a[right] = a[left];//左坑
while(left<right && a[right]>=key)
{
--right;
}
a[left] = a[right];
}
a[left] = key;
return a[left];
}
void QuickSort2(int* a,int left,int right)
{
assert(a);
if(left<right)
{
int div = PartSort2(a,left,right);
QuickSort2(a,left,div-1);
QuickSort2(a,div+1,right);
}
}
//列印函式
void PrintArray(int* a,size_t n)
{
for(size_t i=0;i<n;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
int a[]={2,5,4,0,9,3,6,8,7,1};
PrintArray(a,sizeof(a)/sizeof(a[0]));
QuickSort2(a,0,(sizeof(a)/sizeof(a[0]))-1);
PrintArray(a,sizeof(a)/sizeof(a[0]));
}
方法三:前後指標法
演算法程式碼:
//方法三:前後指標法??若有問題,請指出
int PartSort3(int* a,int left,int right)
{
int cur = left;
int prev = left-1;
int key = a[right];
while(cur<right);
{
if(a[cur]<key && ++prev!=cur)
{
swap(a[cur],a[prev]);
}
++cur;
}
swap(a[++prev],a[right]);
return prev;
}
void QuickSort3(int* a,int left,int right)
{
assert(a);
if(left<right)
{
int div = PartSort3(a,left,right);
QuickSort3(a,left,div-1);
QuickSort3(a,div+1,right);
}
}
//列印函式
void PrintArray(int* a,size_t n)
{
for(size_t i=0;i<n;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
//測試程式碼
void QuickSortTest()
{
int a[]={2,5,4,0,9,3,6,8,7,1};
PrintArray(a,sizeof(a)/sizeof(a[0]));
QuickSort3(a,0,(sizeof(a)/sizeof(a[0]))-1);
PrintArray(a,sizeof(a)/sizeof(a[0]));
}
2.時間複雜度:
最好情況:O(nlogn)
最壞情況:O(n^2)
平均情況:O(nlogn)
空間複雜度:O(nlogn)
3.穩定性:不穩定