您的位置:首页 > 其它

交换排序

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  冒泡 快排 排序