列车车厢重排 思维过程正确性

来源:互联网 发布:全球数据化时代txt 编辑:程序博客网 时间:2024/05/21 15:51

栈实现

[5,8,1,7,4,2,9,6,3]_________________________=>______________[9,8,7,6,5,4,3,2,1]

                                           ③|④|⑤|(buffer/stack)                     |||


操作规则:

(1)①只能一次通过最前面一个车厢,该车厢可以去 buffer中 满足(2)的最前面的stack,或者直接到②。

(2)buffer 区 元素始终保持 小元素在上。

(3)stack 最上面的车厢可以去②。


实现:

#include<stack>#include<vector>using rank_t = unsigned;void sort(std::stack<rank_t>& seq) {std::vector<std::stack<rank_t>> buffers;size_t remainSize = seq.size()+1;std::stack<rank_t> result;result.push(0);rank_t curRank;while (result.size()!=remainSize) {curRank = seq.top();//判断首元素是否可以直接去2区if (curRank == result.top() - 1) {result.push(curRank);seq.pop();remainSize--;}else {//顺序查找需要去哪个缓冲区auto putIT = buffers.begin();while (putIT != buffers.end()) {if (putIT->top() > curRank) {putIT->push(curRank);break;//找到即刻退出}++putIT;}//没找到现有容器符合条件,新建if (putIT == buffers.end()) {buffers.push_back(std::stack<rank_t>());putIT->push(curRank);}}//检查是否有缓冲区元素可去2区for (auto goIT = buffers.begin(); goIT != buffers.end(); ++goIT) {if (goIT->top() == result.top() - 1) {result.push(goIT->top());goIT->pop();remainSize--;}}seq = std::move(result);}}

为什么这种过程是正确的?

操作规则 (1) 和(2) 各有一个顺序性,分别是顺序扫描和小元素在上,这就使栈中的元素归类有减而治之的特性,因此算法是正确的。

举例说明:(沿用文章开始图示的例子)

某一时刻,buffer中各个栈的状态为:


| |      |      |      |     |

|   3  |      |   6  |       |   9  |......——①

接下来应该进入元素5:


| |       |   5 ||       |

|   3 ||   6  ||   9  |......——②


由于顺序性操作,在 6 上的值,一定处于区间  (3 , 6) 内,

此后对外界来说,buffer区的状态就变成了:


| |    |       ||      |

|   3  |      |   5  |       |   9  |......——③


①③对比发现,区间 (3 , 6) 缩窄成了 (3 , 5)

虽然 原先区间 (6 ,  9) 扩宽了,但假设下面进来的元素是 8 ,这个区间也将缩窄


总的来说,这个操作过程就像是在 填数轴,只不过有些元素因为符合结果需要的顺序直接被拿走了。

但这不改变 填数轴过程中 减小规模的特点,所以是正确的。


队列实现

[5,8,1,7,4,2,9,6,3]_①________________②

                                  ↓_____________↑

                                  ↓_____________↑

操作规则:

(1)①只能一次通过最前面一个车厢,该车厢可以去 buffer中 满足(2)的最前面的 queue,或者直接到②。

(2)buffer 区 元素始终保持 大元素在队列末尾。

(3)queue 头元素可以去②。