假设你现在有一串无序数组,并存放在vector(可以看成是数组的扩展,我之前的文章有介绍,不赘述。可以直接引用头文件< vector >)当中:




java中如何将Vector对象中的顺序打乱 给vector排序_排序算法


sort< vec>,使得上述数据能升序排列:


java中如何将Vector对象中的顺序打乱 给vector排序_数据_02


选择排序算法(selection sort algorithm)

算法思路

对于上述的排序,有很多种办法可以做到。这里介绍一种最简单的排序算法——选择排序算法。 选择排序的做法其实很简单:

1. 先遍历所有的元素,在第一轮循环中,找出所有元素中最小的元素,然后与排第一的元素进行交换位置。

2. 接下来第二次遍历的过程中,再在剩下的元素中找到所有元素中最小的元素,与当前排第二的元素交换位置。

3. 反复执行上述过程,直到vector中所有数值都排序准确。

算法实例分析

拿个实例来分析一下,如果要求被排序的是下列的数值


java中如何将Vector对象中的顺序打乱 给vector排序_数据_03


在第一轮算法中,应该是通过第一次循环,找到下标为5的数字,并且与下标为0的数字互换。这样可以得出下列数组排序:


java中如何将Vector对象中的顺序打乱 给vector排序_数据_04


同样的,在第二轮中,找到1-7中最小的数字,下标为1(即25),1与1交换,排序情况不变,vector排列不变。如此反复。最终排出升序数组。

算法实现

下面用C++代码编写选择排序算法,这个算法的关键是如何找到剩余元素的最小值的下标:


#include <iostream>
#include <vector>
using namespace std;
//函数声明
void sort(vector<int> & vec);  //声明要求的函数,使用引用是因为这次排序会改动原有的结构
//主程序
int main(){
    vector<int> vec;
    for (int i = 0; i < 8; i++){
        int n;
        cin >> n;
        vec.push_back(n); //将输入的数据直接放入vector中
    }
    sort(vec); //执行选择排序算法
    for(int k = 0; k < vec.size();k++){
        cout << vec[k] <<" ";
    }
    return 0;
}

/*
*该实现使用称为选择排序的算法,其可以描述如下。
*从左手(lh)边,依次指向vector中的每个元素,
*从下标0开始。在循环中的每个步骤中:
*1.找到你的左手和vector的最后一个范围内的最小元素,并用右手(rh)指向该元素。
*2. 通过交换左手和右手指示的元素将该元素移动到正确的位置
*/
void sort(vector<int> & vec){
    int n = vec.size();
    for(int lh = 0; lh < n; lh++){   //表明这是第几轮
        int rh = lh; //一开始的时候,左右手指向同一个元素,就是第一个元素 
        for(int i = lh + 1; i < n; i++){ //从左手边的剩下的元素开始遍历 
            if(vec[i] < vec[rh]) rh = i;/*如果找到比rh所指的值小,那么rh就指向
                                          它,直到rh指向剩余元素中最小的一个 */ 
        }
        /*最后实现lh与rh的交换,交换放在外循环,目的就是每当lh增加1,那么
         *就执行一次交换,直到lh执行最后一个元素,交换完成
         *也就意味着排序完成
         */ 
        int tmp = vec[lh];
        vec[lh] = vec[rh];
        vec[rh] = tmp;
    }
}


上述代码在VS2015编译通过,运行结果为:


java中如何将Vector对象中的顺序打乱 给vector排序_vector 排序_05


算法性能分析(performance)

选择排序作为排序算法策略,其性能如何?我们先来看看一张表,这张表记录了计算机对各种大小的vector进行排序所需的时间(当然,现在的计算机计算速度那么快,应该已经超出这个速度了,不过这并不影响我们对算法进行分析)。其中N表示vector中元素的数量。


java中如何将Vector对象中的顺序打乱 给vector排序_vector 排序_06


对于10个整数的向量,选择排序算法在几微秒内完成其工作。即使是5000个整数,这种排序的执行不到一秒钟,这在我们的时间感上看起来肯定是够快的。然而,随着要排序的数的量越来越大,选择排序的表现开始下降。 对于10万个整数的vector,算法需要两分半钟以上。如果你坐在你的电脑前等待它的回复,那是一个非常长的时间。

我们可以看到,随着vector大小的增加,选择排序的性能迅速变坏。从时间数据可以看出,每次将值的乘数乘以10时,对vecctor进行排序所需的时间会增加一百倍。如果这种模式继续下去,排序一百万个数字将需要大约四个半小时。对于业务上来说肯定是不行的,那么只能另寻他法。(这个说法我想到一个例子,我们不能只看表面的数据,有时候它并没有太大的意义。一罐可乐,在普通商店2.5元,在火车站里面可能要3块。你说贵吗?也就涨了5毛,还行。但是换个说话,5毛的涨幅是20%,也就是对比外面涨了20%,这种涨幅看起来是很多的。)

那么当N逐渐增大的时候,为什么性能会变得如此之差呢?这就需要我们好好分析一下。我们可以从计算机的角度看看计算机执行一次这样的算法需要做什么。我们对于代码中的两个for循环分步骤来分析:

1. 为了确定vector中的第一个元素,我们需要对所有的N个元素中搜索最小值(因为就算只是搜索N-1个数,但是依旧是要跟第一个元素执行交换操作)。

2. 为了确定vector中的第二个元素,我们需要对所有的N-1个元素中搜索最小值。

3. ....省略步骤....

4. 为了确定vector中的第N个元素,我们需要对所有的1个元素中搜索最小值.

所以总的执行搜索的次数为:


java中如何将Vector对象中的顺序打乱 给vector排序_数据_07


利用等差数列的求和公式,可以得出求和结果:


java中如何将Vector对象中的顺序打乱 给vector排序_搜索_08


或者


java中如何将Vector对象中的顺序打乱 给vector排序_vector排序_09


现在我们再看表格中的数据,取N=10,000这一条,可以很清楚的看到,当N=10000的时候,需要执行50005000次搜索操作(带入上述公式),而表一已经写明了花了1.58s。这样可以大致算出平均每执行一次搜索需要耗时多长:


java中如何将Vector对象中的顺序打乱 给vector排序_数据_10


现在假设每执行一次搜索都耗时等长的时间,那么可以得出下面的一张表


java中如何将Vector对象中的顺序打乱 给vector排序_搜索_11


这表明我们当初的分析是正确的。