排序算法----交换排序(冒泡排序&快速排序)
一、排序算法分为:
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.代码
//冒泡排序
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]));
}
2.时间复杂度:
最好情况: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.稳定性:不稳定