C++编程思想 第2卷 第7章 通用容器 优先队列

当向一个优先队列priority_queue用push()压入一个对象时
那个对象根据一个比较函数或函数对象在队列中排序
priority_queue确定用top()查看顶部元素时
该元素将使具有最高优先级的一个元素

创造一个用来处理int型数据的priority_queue是个很平常的工作

//: C07:PriorityQueue1.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <queue>
using namespace std;

int main() {
  priority_queue<int> pqi;
  srand(time(0)); // Seed the random number generator
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~

输出
24 24 24 23 23 23 23 23 23 22 22 22 22 21 21 21 21 21 21 20 20 19 19 18 18 18 18 18 17 17 17 17 16 16 16 16 16 15 15 15 15 15 14 14 14 14 14 14 13 13 13 13 13 13 13 13 12 12 12 11 11 11 11 11 10 10 10 9 9 9 8 8 7 7 7 6 6 6 5 5 5 5 4 4 4 4 3 2 2 2 2 1 1 1 1 1 0 0 0 0

程序向priority_queue压入100个数值介于0到24之间的随机数
在运行这个程序时
会看到它允许出现重复的值
而且最高值先出现

通过用户自己的函数或函数对象以改变其元素的排列顺序
给予较低值的数以最高的优先级

//: C07:PriorityQueue2.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Changing the priority.
#include <cstdlib>
#include <ctime>
#include <functional>
#include <iostream>
#include <queue>
using namespace std;

int main() {
  priority_queue<int, vector<int>, greater<int> > pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~


输出
0 1 1 1 2 2 2 3 3 3 4 4 5 5 5 6 6 6 6 6 6 6 7 7 7 7 8 8 8 9 9 9 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11 11 12 12 12 12 12 12 13 13 13 14 14 14 14 15 15 15 15 15 16 16 16 16 17 17 17 17 17 18 18 18 18 18 18 18 19 19 19 20 20 20 20 20 21 21 21 21 22 22 22 24 24 24

每个对象都包含一个string
和一个主优先级及一个次优先级的值

//: C07:PriorityQueue3.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// A more complex use of priority_queue.
#include <iostream>
#include <queue>
#include <string>
using namespace std;

class ToDoItem {
  char primary;
  int secondary;
  string item;
public:
  ToDoItem(string td, char pri = 'A', int sec = 1)
  : primary(pri), secondary(sec), item(td) {}
  friend bool operator<(
    const ToDoItem& x, const ToDoItem& y) {
    if(x.primary > y.primary)
      return true;
    if(x.primary == y.primary)
      if(x.secondary > y.secondary)
        return true;
    return false;
  }
  friend ostream&
  operator<<(ostream& os, const ToDoItem& td) {
    return os << td.primary << td.secondary
      << ": " << td.item;
  }
};

int main() {
  priority_queue<ToDoItem> toDoList;
  toDoList.push(ToDoItem("Empty trash", 'C', 4));
  toDoList.push(ToDoItem("Feed dog", 'A', 2));
  toDoList.push(ToDoItem("Feed bird", 'B', 7));
  toDoList.push(ToDoItem("Mow lawn", 'C', 3));
  toDoList.push(ToDoItem("Water lawn", 'A', 1));
  toDoList.push(ToDoItem("Feed cat", 'B', 1));
  while(!toDoList.empty()) {
    cout << toDoList.top() << endl;
    toDoList.pop();
  }
  getchar();
} ///:~

输出
A1: Water lawn
A2: Feed dog
B1: Feed cat
B7: Feed bird
C3: Mow lawn
C4: Empty trash

由于是与less<>一同工作
所以ToDoItem的operator<必须是一个非成员函数
除此之外 每一件事情都是自动发生的

priority_queue使用的容器是protected的
并且有标识符 根据标准C++规格说明 该标识符被命名为c
所以可以继承一个新类

//: C07:PriorityQueue4.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Manipulating the underlying implementation.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <queue>
using namespace std;

class PQI : public priority_queue<int> {
public:
  vector<int>& impl() { return c; }
};

int main() {
  PQI pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  copy(pqi.impl().begin(), pqi.impl().end(),
    ostream_iterator<int>(cout, " "));
  cout << endl;
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~

输出
24 24 22 23 23 18 18 21 21 21 22 14 13 14 13 15 19 20 18 11 14 20 21 12 11 5 12 13 12 11 11 9 13 9 15 11 18 8 12 5 5 14 14 18 15 19 19 7 9 8 9 0 1 2 3 4 5 4 8 3 8 1 11 0 8 1 2 7 8 5 14 2 8 7 10 1 3 6 10 1 4 3 1 7 13 12 1 5 8 2 7 7 19 16 0 4 5 3 6 6
24 24 23 23 22 22 21 21 21 21 20 20 19 19 19 19 18 18 18 18 18 16 15 15 15 14 14 14 14 14 14 13 13 13 13 13 12 12 12 12 12 11 11 11 11 11 11 10 10 9 9 9 9 8 8 8 8 8 8 8 8 7 7 7 7 7 7 6 6 6 5 5 5 5 5 5 5 4 4 4 4 3 3 3 3 3 2 2 2 2 1 1 1 1 1 1 1 0 0 0

当调用pop()时
得到的这个vector包含的元素并不是按降序排列
就是想要从优先队列得到的顺序

//: C07:PriorityQueue5.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Building your own priority queue.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <queue>
using namespace std;

template<class T, class Compare>
class PQV : public vector<T> {
  Compare comp;
public:
  PQV(Compare cmp = Compare()) : comp(cmp) {
    make_heap(this->begin(),this->end(), comp);
  }
  const T& top() { return this->front(); }
  void push(const T& x) {
    this->push_back(x);
    push_heap(this->begin(),this->end(), comp);
  }
  void pop() {
    pop_heap(this->begin(),this->end(), comp);
    this->pop_back();
  }
};

int main() {
  PQV< int, less<int> > pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  copy(pqi.begin(), pqi.end(),
    ostream_iterator<int>(cout, " "));
  cout << endl;
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~


输出
24 24 24 23 24 22 22 23 21 23 24 20 20 21 20 23 17 19 18 17 21 21 22 19 18 10 19 15 19 13 12 10 22 4 16 13 15 11 10 10 10 14 17 17 21 8 12 14 15 13 15 4 7 0 8 1 9 5 5 5 3 7 9 3 9 1 9 1 4 2 3 8 0 3 14 6 6 3 5 4 1 4 6 6 3 5 12 10 14 5 0 2 4 4 5 6 14 8 0 5
24 24 24 24 24 23 23 23 23 22 22 22 22 21 21 21 21 21 20 20 20 19 19 19 19 18 18 17 17 17 17 16 15 15 15 15 14 14 14 14 14 13 13 13 12 12 12 11 10 10 10 10 10 10 9 9 9 9 8 8 8 8 7 7 6 6 6 6 6 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 3 3 3 3 3 3 2 2 1 1 1 1 0 0 0 0

在vector底层中的一个被称为堆 heap的存储区
这个堆数据结构表现为一个优先队列的树的结构
在对其从头到尾进行迭代的时候
并不会得到一个线性的优先队列顺序

//: C07:PriorityQueue6.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <queue>
using namespace std;

template<class T, class Compare>
class PQV : public vector<T> {
  Compare comp;
  bool sorted;
  void assureHeap() {
    if(sorted) {
      // Turn it back into a heap:
      make_heap(this->begin(),this->end(), comp);
      sorted = false;
    }
  }
public:
  PQV(Compare cmp = Compare()) : comp(cmp) {
    make_heap(this->begin(),this->end(), comp);
    sorted = false;
  }
  const T& top() {
    assureHeap();
    return this->front();
  }
  void push(const T& x) {
    assureHeap();
    this->push_back(x); // Put it at the end
    // Re-adjust the heap:
    push_heap(this->begin(),this->end(), comp);
  }
  void pop() {
    assureHeap();
    // Move the top element to the last position:
    pop_heap(this->begin(),this->end(), comp);
    this->pop_back();// Remove that element
  }
  void sort() {
    if(!sorted) {
      sort_heap(this->begin(),this->end(), comp);
      reverse(this->begin(),this->end());
      sorted = true;
    }
  }
};

int main() {
  PQV< int, less<int> > pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++) {
    pqi.push(rand() % 25);
    copy(pqi.begin(), pqi.end(),
      ostream_iterator<int>(cout, " "));
    cout << "\n-----" << endl;
  }
  pqi.sort();
  copy(pqi.begin(), pqi.end(),
    ostream_iterator<int>(cout, " "));
  cout << "\n-----" << endl;
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~

输出
23
-----
23 16
-----
23 16 19
-----
23 20 19 16
-----
23 20 19 16 18
-----
23 20 19 16 18 15
-----
23 20 21 16 18 15 19
-----
23 20 21 16 18 15 19 11
-----
23 20 21 16 18 15 19 11 13
-----
23 20 21 16 18 15 19 11 13 14
-----
23 20 21 16 18 15 19 11 13 14 3
-----
23 20 21 16 18 15 19 11 13 14 3 14
-----
23 20 21 16 18 15 19 11 13 14 3 14 10
-----
23 20 21 16 18 15 19 11 13 14 3 14 10 17
-----
23 20 21 16 18 15 19 11 13 14 3 14 10 17 18
-----
23 20 21 16 18 15 19 11 13 14 3 14 10 17 18 2
-----
23 20 21 16 18 15 19 11 13 14 3 14 10 17 18 2 3
-----
23 20 21 16 18 15 19 11 16 14 3 14 10 17 18 2 3 13
-----
23 20 21 16 18 15 19 11 16 14 3 14 10 17 18 2 3 13 1
-----
23 20 21 16 18 15 19 11 16 14 3 14 10 17 18 2 3 13 1 3
-----
23 20 21 16 18 15 19 11 16 14 3 14 10 17 18 2 3 13 1 3 11
-----
23 23 21 16 20 15 19 11 16 14 18 14 10 17 18 2 3 13 1 3 11 3
-----
23 23 21 16 20 15 19 11 16 14 18 14 10 17 18 2 3 13 1 3 11 3 17
-----
23 23 21 16 20 15 19 11 16 14 18 14 10 17 18 2 3 13 1 3 11 3 17 7
-----
23 23 21 16 20 17 19 11 16 14 18 15 10 17 18 2 3 13 1 3 11 3 17 7 14
-----
23 23 21 16 20 17 19 11 16 14 18 15 16 17 18 2 3 13 1 3 11 3 17 7 14 10
-----
23 23 21 16 20 17 19 11 16 14 18 15 16 17 18 2 3 13 1 3 11 3 17 7 14 10 10
-----
23 23 21 16 20 17 19 11 16 14 18 15 16 17 18 2 3 13 1 3 11 3 17 7 14 10 10 4
-----
23 23 21 16 20 17 19 11 16 14 18 15 16 17 18 2 3 13 1 3 11 3 17 7 14 10 10 4 3
-----
23 23 21 16 20 17 21 11 16 14 18 15 16 17 19 2 3 13 1 3 11 3 17 7 14 10 10 4 3 18
-----
23 23 21 16 20 17 21 11 16 14 18 15 16 17 19 2 3 13 1 3 11 3 17 7 14 10 10 4 3 18 19
-----
23 23 21 22 20 17 21 16 16 14 18 15 16 17 19 11 3 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2
-----
23 23 21 22 20 17 21 16 16 14 18 15 16 17 19 11 3 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2 10
-----
23 23 21 22 20 17 21 22 16 14 18 15 16 17 19 11 16 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3
-----
23 23 21 22 20 17 21 22 16 14 18 15 16 17 19 11 21 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16
-----
23 23 21 22 20 17 21 22 16 14 18 15 16 17 19 11 21 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2
-----
23 23 21 22 20 17 21 22 16 14 18 15 16 17 19 11 21 13 1 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 16 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 3 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3 6
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3 6 1
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 3 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3 6 1 2
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 8 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3 6 1 2 3
-----
24 23 21 23 20 17 21 22 22 14 18 15 16 17 19 11 21 13 22 6 11 12 17 7 14 10 10 4 3 18 19 2 10 3 16 2 9 1 16 3 6 1 2 3 8 
太多了省略

如果sorted为真
vector就不是作为一个堆来进行组织的
而仅仅是个排过序的序列
函数assureHeap()保证在对其进行任何堆操作之前使其倒退成为一个堆的形式

创建一个非vector的优先队列
每当需要时就构建一个使用vector的优先队列

//: C07:PriorityQueue7.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// A priority queue that will hand you a vector.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <queue>
#include <vector>
using namespace std;

template<class T, class Compare> class PQV {
  vector<T> v;
  Compare comp;
public:
  // Don't need to call make_heap(); it's empty:
  PQV(Compare cmp = Compare()) : comp(cmp) {}
  void push(const T& x) {
    v.push_back(x); // Put it at the end
    // Re-adjust the heap:
    push_heap(v.begin(), v.end(), comp);
  }
  void pop() {
    // Move the top element to the last position:
    pop_heap(v.begin(), v.end(), comp);
    v.pop_back(); // Remove that element
  }
  const T& top() { return v.front(); }
  bool empty() const { return v.empty(); }
  int size() const { return v.size(); }
  typedef vector<T> TVec;
  TVec getVector() {
    TVec r(v.begin(), v.end());
    // It's already a heap
    sort_heap(r.begin(), r.end(), comp);
    // Put it into priority-queue order:
    reverse(r.begin(), r.end());
    return r;
  }
};

int main() {
  PQV<int, less<int> > pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  const vector<int>& v = pqi.getVector();
  copy(v.begin(), v.end(),
    ostream_iterator<int>(cout, " "));
  cout << "\n-----------" << endl;
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~

输出
24 24 24 24 23 23 23 23 23 23 23 22 21 21 21 20 20 19 19 18 18 18 18 18 18 16 16 16 16 15 15 15 14 14 14 14 13 13 13 13 13 13 13 13 12 12 12 12 11 11 10 10 10 10 10 10 10 9 8 8 8 8 8 7 7 7 7 7 7 7 7 6 6 6 6 5 5 5 5 4 4 3 3 3 3 2 2 2 2 2 1 1 1 1 0 0 0 0 0 0
-----------
24 24 24 24 23 23 23 23 23 23 23 22 21 21 21 20 20 19 19 18 18 18 18 18 18 16 16 16 16 15 15 15 14 14 14 14 13 13 13 13 13 13 13 13 12 12 12 12 11 11 10 10 10 10 10 10 10 9 8 8 8 8 8 7 7 7 7 7 7 7 7 6 6 6 6 5 5 5 5 4 4 3 3 3 3 2 2 2 2 2 1 1 1 1 0 0 0 0 0 0

PQV类模板随后采用了与STL的priority_queue相同的形式
但是拥有一个附加的成员函数getVector()
该函数创建一个从PQV中复制来的新的vector

//: C07:PriorityQueue8.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// A more compact version of PriorityQueue7.cpp.
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <queue>
using namespace std;

template<class T> class PQV : public priority_queue<T> {
public:
  typedef vector<T> TVec;
  TVec getVector() {
    TVec r(this->c.begin(),this->c.end());
    // c is already a heap
    sort_heap(r.begin(), r.end(), this->comp);
    // Put it into priority-queue order:
    reverse(r.begin(), r.end());
    return r;
  }
};

int main() {
  PQV<int> pqi;
  srand(time(0));
  for(int i = 0; i < 100; i++)
    pqi.push(rand() % 25);
  const vector<int>& v = pqi.getVector();
  copy(v.begin(), v.end(),
    ostream_iterator<int>(cout, " "));
  cout << "\n-----------" << endl;
  while(!pqi.empty()) {
    cout << pqi.top() << ' ';
    pqi.pop();
  }
  getchar();
} ///:~


输出
24 24 24 23 23 23 23 23 22 22 22 22 21 21 21 20 19 19 19 19 18 18 18 17 17 17 17 17 17 16 16 16 15 15 15 15 14 14 14 14 14 14 14 14 13 13 13 13 12 12 12 12 12 11 11 10 10 9 9 9 9 9 9 9 8 8 7 6 6 5 5 5 5 5 5 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 0 0
-----------
24 24 24 23 23 23 23 23 22 22 22 22 21 21 21 20 19 19 19 19 18 18 18 17 17 17 17 17 17 16 16 16 15 15 15 15 14 14 14 14 14 14 14 14 13 13 13 13 12 12 12 12 12 11 11 10 10 9 9 9 9 9 9 9 8 8 7 6 6 5 5 5 5 5 5 4 4 4 4 4 4 3 3 3 3 3 2 2 2 2 2 2 1 1 1 1 1 1 0 0

保证用户不会得到一个处在未经排序状态的vector
使它变得简单且最令人期待
唯一潜在的问题就是成员函数getVector()采用传值的方式返回vector<T>

猜你喜欢

转载自blog.csdn.net/eyetired/article/details/82530800