交换排序
2018-01-25 22:48
211 查看
交换排序分为冒泡排序和快速排序。
冒泡排序:
它是一种比较简单的排序方法,相邻两个元素两两比较,如果后一个比前一个大,就交换,每趟排序都可以将大的元素“浮”到顶端。外层循环循环n-1次,相当于排好了最大的n-1个元素的位置,则最后一个元素的位置就确定了。内层循环循环n-i次,两两交换,第一次排出最大元素在a[n-1]处;第二次循环n-1次,最大元素在a[n-2]处。
时间复杂度:
最好的情况:有序的,需要进行n-1次比较,O(n)
最坏的情况:逆序的,第一趟进行n-1次比较,第二趟进行n-2次比较,......进行1次比较。总共需要n*(n-1)/2次比较,则时间复杂度为O(n^2)
算法稳定性:
冒泡排序是将小的元素调到前面,大的元素调到后面。相邻两元素比较,交换,相等就不交换,因此算法的是稳定的。
void BubbleSort(int a[],size_t n)
{
int i,j,temp;
for(i = 0;i < n-1;++i) //进行n-1次外层循环
{
for(j = 0;j < n-1-i;++j)
{
if(a[j] > a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
void TestBubbleSort()
{
int a[] = {12,23,6,9,18,22,35,120,89,67};
BubbleSort(a,sizeof(a)/sizeof(a[0]));
PrintArray(a,sizeof(a)/sizeof(a[0]));
}运行结果:
快速排序:
设要排序的数组为a[0],a[1],a[2],a[3],......,a[n-1],任取一个数据作为关键字(通常是数组的第一个元素),一趟快速排序下来,比它大的数放在它的前面,比它小的数放在它的后面,对左右区间重复快排,直到各区间只有一个数。
时间复杂度:
最好的情况:若数组有n个元素,算出支点key的位置,再递归调用左半部分和右半部分,第一层递归 n/2 ,n/2 ,第二层递归 4/n ,4/n ,4/n ,4/n ,则n个元素递归共需x层 :2^x = n , x=logn , 每层都是n的复杂度,则时间复杂度为O(nlogn)。
最坏的情况:有序数组,则比较次数为n-1+n-2+n-3+……+1=n(n-1)/2=O(n^2)
快速排序是不稳定的一种算法,两个相同的值在排序过程中的先后顺序有可能改变。
代码实现:
快速排序(左右指针法)
begin为左指针,end为右指针
//[begin,end]
int Partition(int* a,int begin,int end)
{
int& key = a[end]; //key是a[end]的别名,使用引用更高效
while(begin < end)
{
while(begin < end && a[begin] <= key)
++begin; //begin找大
while(begin < end && a[end] >= key)
--end; //end找小
if(begin < end)
swap(a[begin],a[end]);
}
//当出了循环,begin=end时,此时a[begin]一定大于key,a[begin]和key交换,key就在“中间”的位置
swap(a[begin],key);
return begin;
}
void QuickSort(int* a,int left,int right)
{
if(left >= right)
return;
int div = Partition(a,left,right); //div是选出来的关键数字,其左边的数比它小,右边的数字比他大
QuickSort(a,left,div-1); 对div左右两边的区间再进行快排
QuickSort(a,div+1,right);
}
void TestQuickSort()
{
int a[] = {12,17,18,3,9,7,4,29,53,6};
//int a[] = {7,4,21,8,16,19,20,9,10};
QuickSort(a,0,sizeof(a)/sizeof(a[0])-1);
PrintArray(a,sizeof(a)/sizeof(a[0]));
}
运行结果:
改进:快速排序(左右指针法)
对于支点key的选取----采用三数取中法,使key两边的数更加接近五五分。
int GetMidIndex(int* a,int left,int right)
{
//三数取中法
int mid = left + (right-left)/2;
if(a[left] < a[mid])
{
if(a[left] > a[right])
return left;
else if(a[left] < a[right])
return right;
else
return mid;
}
else
{
if(a[mid] > a[right])
return mid;
else if(a[mid] < a[right])
return right;
else
return left;
}
}
//左右指针法[left,right]
int Partition(int* a,int begin,int end)
{
int mid = GetMidIndex(a,begin,end);
swap(a[mid],a[end]);
int& key = a[end];
while(begin < end)
{
//begin找大
while(begin < end && a[begin] <= key)
++begin;
while(begin < end && a[end] >= key)
--end;
//end找小
if(begin < end)
swap(a[begin],a[end]);
}
swap(a[begin],key);
return begin;
}
快速排序(挖坑法)
begin找比key大的数,把a[begin]赋给a[end],begin处为新坑,end找比key小的数,a[end]赋给a[begin],end处为新坑。
//挖坑法[left,right]
int Partition(int* a,int begin,int end)
{
int& key = a[end];
while(begin < end)
{
while(begin < end && a[begin] >= key)
++begin;
if(begin < end)
a[end] = a[begin];
while(begin < end && a[end] <= key)
--end;
if(begin < end)
a[begin] = a[end];
}
a[begin] = key;
return begin;
}快速排序(前后指针法)int Partition(int* a,int left,int right)
{
int prev = left-1;
int cur = left;
while(cur < right)
{
if(a[cur] < a[right] && ++prev !=cur)
{
swap(a[cur],a[prev]);
}
++cur;
}
swap(a[right],a[++prev]);
return prev;
}
冒泡排序:
它是一种比较简单的排序方法,相邻两个元素两两比较,如果后一个比前一个大,就交换,每趟排序都可以将大的元素“浮”到顶端。外层循环循环n-1次,相当于排好了最大的n-1个元素的位置,则最后一个元素的位置就确定了。内层循环循环n-i次,两两交换,第一次排出最大元素在a[n-1]处;第二次循环n-1次,最大元素在a[n-2]处。
时间复杂度:
最好的情况:有序的,需要进行n-1次比较,O(n)
最坏的情况:逆序的,第一趟进行n-1次比较,第二趟进行n-2次比较,......进行1次比较。总共需要n*(n-1)/2次比较,则时间复杂度为O(n^2)
算法稳定性:
冒泡排序是将小的元素调到前面,大的元素调到后面。相邻两元素比较,交换,相等就不交换,因此算法的是稳定的。
void BubbleSort(int a[],size_t n)
{
int i,j,temp;
for(i = 0;i < n-1;++i) //进行n-1次外层循环
{
for(j = 0;j < n-1-i;++j)
{
if(a[j] > a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
void TestBubbleSort()
{
int a[] = {12,23,6,9,18,22,35,120,89,67};
BubbleSort(a,sizeof(a)/sizeof(a[0]));
PrintArray(a,sizeof(a)/sizeof(a[0]));
}运行结果:
快速排序:
设要排序的数组为a[0],a[1],a[2],a[3],......,a[n-1],任取一个数据作为关键字(通常是数组的第一个元素),一趟快速排序下来,比它大的数放在它的前面,比它小的数放在它的后面,对左右区间重复快排,直到各区间只有一个数。
时间复杂度:
最好的情况:若数组有n个元素,算出支点key的位置,再递归调用左半部分和右半部分,第一层递归 n/2 ,n/2 ,第二层递归 4/n ,4/n ,4/n ,4/n ,则n个元素递归共需x层 :2^x = n , x=logn , 每层都是n的复杂度,则时间复杂度为O(nlogn)。
最坏的情况:有序数组,则比较次数为n-1+n-2+n-3+……+1=n(n-1)/2=O(n^2)
快速排序是不稳定的一种算法,两个相同的值在排序过程中的先后顺序有可能改变。
代码实现:
快速排序(左右指针法)
begin为左指针,end为右指针
//[begin,end]
int Partition(int* a,int begin,int end)
{
int& key = a[end]; //key是a[end]的别名,使用引用更高效
while(begin < end)
{
while(begin < end && a[begin] <= key)
++begin; //begin找大
while(begin < end && a[end] >= key)
--end; //end找小
if(begin < end)
swap(a[begin],a[end]);
}
//当出了循环,begin=end时,此时a[begin]一定大于key,a[begin]和key交换,key就在“中间”的位置
swap(a[begin],key);
return begin;
}
void QuickSort(int* a,int left,int right)
{
if(left >= right)
return;
int div = Partition(a,left,right); //div是选出来的关键数字,其左边的数比它小,右边的数字比他大
QuickSort(a,left,div-1); 对div左右两边的区间再进行快排
QuickSort(a,div+1,right);
}
void TestQuickSort()
{
int a[] = {12,17,18,3,9,7,4,29,53,6};
//int a[] = {7,4,21,8,16,19,20,9,10};
QuickSort(a,0,sizeof(a)/sizeof(a[0])-1);
PrintArray(a,sizeof(a)/sizeof(a[0]));
}
运行结果:
改进:快速排序(左右指针法)
对于支点key的选取----采用三数取中法,使key两边的数更加接近五五分。
int GetMidIndex(int* a,int left,int right)
{
//三数取中法
int mid = left + (right-left)/2;
if(a[left] < a[mid])
{
if(a[left] > a[right])
return left;
else if(a[left] < a[right])
return right;
else
return mid;
}
else
{
if(a[mid] > a[right])
return mid;
else if(a[mid] < a[right])
return right;
else
return left;
}
}
//左右指针法[left,right]
int Partition(int* a,int begin,int end)
{
int mid = GetMidIndex(a,begin,end);
swap(a[mid],a[end]);
int& key = a[end];
while(begin < end)
{
//begin找大
while(begin < end && a[begin] <= key)
++begin;
while(begin < end && a[end] >= key)
--end;
//end找小
if(begin < end)
swap(a[begin],a[end]);
}
swap(a[begin],key);
return begin;
}
快速排序(挖坑法)
begin找比key大的数,把a[begin]赋给a[end],begin处为新坑,end找比key小的数,a[end]赋给a[begin],end处为新坑。
//挖坑法[left,right]
int Partition(int* a,int begin,int end)
{
int& key = a[end];
while(begin < end)
{
while(begin < end && a[begin] >= key)
++begin;
if(begin < end)
a[end] = a[begin];
while(begin < end && a[end] <= key)
--end;
if(begin < end)
a[begin] = a[end];
}
a[begin] = key;
return begin;
}快速排序(前后指针法)int Partition(int* a,int left,int right)
{
int prev = left-1;
int cur = left;
while(cur < right)
{
if(a[cur] < a[right] && ++prev !=cur)
{
swap(a[cur],a[prev]);
}
++cur;
}
swap(a[right],a[++prev]);
return prev;
}
相关文章推荐
- 交换排序
- 几种常见的排序算法---交换排序
- 交换排序(快速排序)
- 【排序】02.交换排序(升序)
- 软考之排序算法(三)——交换排序
- 个人学习整理:C++版交换排序
- 冒泡算法及改进(属于交换排序)
- 交换排序---快速排序算法(Javascript版)
- 交换排序—冒泡排序(Bubble Sort)
- 交换排序-快速排序
- 交换排序------冒泡排序
- 排序算法——交换排序
- 排序算法Java——交换排序(之快速排序)
- 交换排序(1)---冒泡排序
- 交换排序-冒泡排序
- 交换排序之冒泡排序与快速排序
- 交换排序---冒泡、快速、归并排序
- 简单的排序算法——插入排序,选择排序,交换排序(冒泡排序,快速排序)
- 排序算法总结(3)——交换排序
- 算法和数据结构——交换排序(冒泡和快速)