排序-冒泡排序及优化

冒泡排序

在每一轮循环中,依次比较相邻的元素。如果是 从大到小排序,则每次将两个元素中较大的一个元素往后交换;如果是从小到大排序,则每次将两个元素中较小的一个元素往前交换。

图1——冒泡排序的模拟示意图

 输入待排序数组:array[4, 6, 5, 8, 9, 3, 2, 1, 7],在这里默认是从小到大排序。

原始版本1

  1. 时间复杂度O(n^2),空间复杂度O(1)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;

int main()
{
    vector<int>a(9);
    int n = 9;
    for(int i=0; i<n; i++)
    {
        cin >> a[i];
    }
    for(int i=0; i<n; i++)
    {
        for(int j = 0; j < n-i-1; j++)
        {

            if(a[j] > a[j+1])
                swap(a[j+1], a[j]);
        }
    }
    for(int i=0;i<n;i++)
    {
        cout << a[i] <<' ';
    }
    cout << endl;
    return 0;
}

图2——冒泡排序原始版本的排序过程

优化版本1

根据原始版本的排序过程,观察图2 的示意图。可以发现:当 i = 7时,已经得出结果,i = 8 的循环过程就不用进行。(这个给的数据不是很好,比如在 i = 3时,数据就已经有序了,那么接下来的几次外部循环就不用进行了,那么我们考虑如果出现这样的情况下,怎么去优化 操作的次数)

  1. 设定一个变量 flag = true。
  2. 如果在某一个循环中,如果相邻的两个数之间发生交换,那么flag = false。
  3. 如果,一个循环后,所有相邻的数据之间都没有发生变化,那么flag = true 不变。此时就跳出循环。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;

int main()
{

    vector<int>a(9);
    int n = 9;
    for(int i=0; i<n; i++)
    {
        cin >> a[i];
    }
    for(int i=0; i<n; i++)
    {
        bool flag = true;
        for(int j=0; j<n-i-1; j++)
        {

            if(a[j] > a[j+1])
            {
                swap(a[j+1], a[j]);
                flag = false;
            }

        }
        if(flag)
            break;
    }
    for(int i=0; i<n; i++)
    {
        cout << a[i] << ' ';
    }
    cout << endl;
    return 0;
}

优化版本2

这里,首先理解一下有序区间的概念:数组有序的区域。比如array[4,5,3,6,2,1,7,8,9],则[7,8,9]可以认为是有序的区域。当存在有序区间时,那么在每一个循环中就不必对有序区间进行判断是否需要交换操作了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;

int main()
{
    vector<int>a(9);
    int n = 9;
    for(int i=0; i<n; i++)
    {
        cin>>a[i];
    }

    int LastIndex = 0;
    int border = a.size()-1;
    for(int i=0; i<n; i++)
    {
        bool flag = true;
        for(int j=0; j<border; j++)
        {
            if(a[j] > a[j+1])
            {
                swap(a[j+1], a[j]);
                LastIndex = j;
                flag = false;
            }
        }
        border = LastIndex;
        if(flag)
            break;
    }

    for(int i=0; i<n; i++)
    {
        cout<< a[i] <<' ';
    }
    cout << endl;
    return 0;
}

 程序中使用两个变量,

  1. border:表示无需区域的边界,即为每一轮循环的比较次数的设定界限。
  2. LastIndex:记录每一轮循环中,元素交换的下标值。

上图中,当i= 6时,就不用再进行数据之间的比较了。减少了比较操作的次数。

优化版本3:鸡尾酒算法排序

是冒泡排序的变形,一轮从左到右排序,下一轮则从右向左排序。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;


int main()
{
    vector<int>a(9);
    int n = 9;
    for(int i=0; i<n; i++)
    {
        cin>>a[i];
    }

    for(int i=0; i<n; i++)
    {
        bool flag = true;
        if(i % 2 == 0)
        {
            for(int j=0; j<n-i-1; j++)
            {
                if(a[j] > a[j+1])
                {
                    swap(a[j+1], a[j]);
                    flag = false;
                }
            }
        }
        else
        {
            for(int j=n-i-1; j>0; j--)
            {
                if(a[j] < a[j-1])
                {
                    swap(a[j], a[j-1]);
                    flag = false;
                }
            }
        }

        if(flag)
            break;
    }

    for(int i=0; i<n; i++)
    {
        cout<< a[i] <<' ';
    }
    cout << endl;
    return 0;
}

如有错误,还请指正。

猜你喜欢

转载自blog.csdn.net/wchzh2015/article/details/88776869