排序算法之插入排序

本篇博客介绍一种对于少量元素的排序方法。整个过程类似用于我们平常打扑克牌。假定桌上有扑克牌若干。我们每次抽一张牌,要求手中的牌时刻都是按照某一顺序(从大到小或者从小到大)的顺序排列。这种过程被称为插入排序。

问题定义

问题输入:n个数的一个序列< a 1 , a 2 ,……, a n >
问题输出:输入序列的一个排列< a 1 , a 2 ,……, a n >

循环不变式

在《算法导论》第三版中提到了“循环不变式”的概念。
继续使用上述扑克牌的例子。下标j指出正被插入到手中的“当前牌”。在for循环的每次迭代的开始,包含元素A[1..j-1]的子数组构成了当前排序好的左手中的牌,剩余的子数组A[j+1..n]对应于桌子上的牌堆。我们可以看出,当前元素A[1..j-1]就是原来在位置1到j-1的元素,并且已经排好序。我们把A[1..j-1]的这些性质表示为一个循环不变式。
循环不变式主要用来帮助理解算法的正确性。关于循环不变式,有如下三条性质:
初始化:循环的第一次迭代之前,它为真。
保持:如果循环的某次迭代之前它为真,那么下次迭代之前它为真。
终止:在循环终止时,不变式可以证明该算法是正确的。
插入排序对于这些性质是成立的。

具体代码

//插入排序由小到大的顺序排列
void Insert_sort(vector<int> &vec)
{
    int n = vec.size();
    for (int i = 1; i < n; i++)
    {
        int key = vec[i];
        int j = i - 1;
        while (j>=0 && vec[j]>key)
        {
            vec[j + 1] = vec[j];
            j--;
        }
        vec[j + 1] = key;
    }
}
//插入排序由大到小的顺序排列
void Insert_sort_two(vector<int> &vec)
{
    int n = vec.size();
    for (int i = 1; i < n; i++)
    {
        int key = vec[i];
        int j = i - 1;
        while (j >= 0 && vec[j]<key)
        {
            vec[j + 1] = vec[j];
            j--;
        }
        vec[j + 1] = key;
    }
}
void show(vector<int> vec)
{
    vector<int>::iterator it = vec.begin();
    for (; it != vec.end(); it++)
    {

        cout << *it << " ";
    }
    cout << endl;
}
int main()
{
    vector<int> vec;
    for (int i =5; i >=0; i--)
    {
        vec.push_back(i);
    }
    show(vec);
    Insert_sort(vec);
    Insert_sort_two(vec);
    show(vec);
    return 0;
}

时间复杂度

假定给定序列<1,2,3,4,5>,要求按照从小到大的顺序排列。则代码中只涉及其中一层循环,即该运行时间是问题规模n 的线性函数。
假定给定序列<5,4,3,2,1>,要求按照从大到小的顺序排列。则代码中涉及到两层循环,即该运行时间是问题规模n的二次函数。
相比之下,存在两类情况分析。最好情况下时间复杂度为O(n),最坏情况下的时间复杂度为O( n 2 ).

猜你喜欢

转载自blog.csdn.net/u013266600/article/details/80756530