显示C ++程序中进程完成的百分比

时间:2016-03-16 22:38:45

标签: c++ algorithm function io percentage

我正在制作一套C ++库作为我的数据结构分配的一部分,其中包括矢量,排序算法,堆栈等的自定义实现。我应该研究排序算法的运行时间,冒泡排序,选择排序,快速排序等,这是我的图书馆的一部分。

现在用于测试算法的数据集大约为10 ^ 6。我对2 * 10 ^ 6个元素的数据进行冒泡排序,程序运行大约需要138分钟,而且在这段时间里,我不知道我的排序算法是否正常工作,或者是不是甚至工作与否。我想在排序功能中添加另一个功能,即它们可以显示完成排序的百分比,我认为这是可能的,因为像冒泡排序这样的算法是确定性的。

一旦我开始这个过程,我需要一个像某些东西出现的消息:

  

正在进行冒泡排序。完成:17%

此百分比由算法确定。考虑具有10000个元素的冒泡排序示例。如果你看一下冒泡排序算法(参见这里:https://en.wikipedia.org/wiki/Bubble_sort),它有2个循环,并且在主循环的每次迭代之后,一个元素被固定到排序数组中的正确位置。因此,在进行1次迭代后,百分比应该增加0.01%。

虽然这个百分比计算存在一个问题,在这种情况下,百分比增加的时间会继续减少,但这样的事情会发生。

此外,该号码应在需要时在同一地点增加。但我不知道如何实现它。

2 个答案:

答案 0 :(得分:1)

对于bubblesort的特殊情况,你可以获取你拥有的元素数量,然后除以100.如果你有552个元素,那么你将得到5.(整数有意义使用)。然后,在你的循环中有一个计数器。如果计数器是5的倍数(你到目前为止已经排序了5个元素),那么你可以将百分比增加1并打印出来。打印它以使百分比显示在现场而不是在下面打印,您可以打印退格!或者尝试使用ncurses库,尽管这可能有点过分。最后,另一种方法可能是使用长度为50个字符或类似的Linux样式进度条。

答案 1 :(得分:1)

您可以将泛型类型的回调函数传递给bubblesort函数,并以合理的间隔调用该函数。

这会影响性能,但无论如何,当你使用bubblesort时,这不应该是一个问题。

首先我们需要一些包括:

#include <iostream>
#include <vector>
#include <random>
#include <chrono>

然后是bubblesort函数,我基本上是从维基百科中获取的:https://en.wikipedia.org/wiki/Bubble_sort#Optimizing_bubble_sort

template <typename T, typename Func>
void bubblesort(std::vector<T> &v, Func callback) {
    size_t const len = v.size();
    size_t n = v.size();
    while(n > 0) {
        size_t newn = 0;
        for(size_t i = 1; i <= n-1; ++i) {
            if (v[i - 1] > v[i]) {
                std::swap(v[i-1], v[i]);
                newn = i;
            }
        }
        n = newn;
        callback(100-static_cast<int>(n*100/len));
    }
}

只要在一个元素中进行排序,我们就会调用给定的回调函数(或在对象上使用operator())。

我们传递的参数是我们到达目标的整数百分比。请注意,由于整数运算,您无法使用n * 100 / v.size()更改操作的顺序,否则它将始终为0,因为n将始终小于v.size();

using namespace std::chrono; //to avoid the horrible line becoming even longer

int main() {
    std::vector<int> vec; 

    /* fill vector with some data */
    std::mt19937 generator(static_cast<unsigned long>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count())); //oh god
    for(int i = 0; i < 100000; ++i) {
        vec.push_back(static_cast<int>(generator()));
    }

对于初始化,我们创建一个随机数生成器并使用当前时间播种它。然后我们在向量中放入一些元素。

    char const *prefix = "Bubble sort under progress. Done: ";
    int lastp = -1;
    bubblesort(vec, [&lastp,prefix](int p){
        //if progress has changed, update it
        if(p != lastp) {
            lastp = p;
            std::cout << "\r" << prefix << p << "%" << std::flush;
            /*std::flush is needed when we don't start a new line
              '\r' puts the cursor to the start of the line */
        }
    });

    std::cout << "\r" << prefix << "100%" << std::endl;
    //make sure we always end on 100% and end the line
}

现在是核心部分:我们将一个C ++ lambda函数作为回调传递给我们的bubblesort函数。然后我们的bubblesort函数将使用百分比值调用此lambda并将其写入屏幕。

瞧,我们得到了一些整洁的输出:

https://youtu.be/iFGN8Wy9T3o

结账单:

你当然可以将lamda函数集成到sort函数本身,但是我不建议这样做,因为你失去了很多灵活性。但这是一个由您自己决定的设计选择 - 如果您不需要灵活性,只需对其进行硬编码即可。

百分比不是很准确,事实上知道你达到20%(以及到达那里需要多长时间)并没有告诉你多少时间可以达到100%,因为它可能很好的是,矢量的最后20%被排序(因此很快用bubblesort -O(n)排序),但剩下的80%是随机的,并取O(n ^ 2)进行排序。 事实上,它告诉你的是你正在取得进步,但这就是你想要的一切,所以我猜这没关系。

如果您想要更准确的百分比调整您的程序,请执行以下操作:

#include <iomanip>
/* ... */
callback(10000-static_cast<int>(n*10000/len));
/* ... */
std::cout.fill('0'); //to fill leading zero of p%100
std::cout << "\r" << prefix << p/100 << "." << std::setw(2) << p%100 << "%" << std::flush;

如果您决定使用浮点值,请记住清除先前输出中的剩余字符 - “\ r \ n”仅重置光标位置,但不清除该行。

使用std::cout.precision(3);获得固定精度,或在信息后写一些空格以清除之前的运行。