[C++] The basic concept of priority queue and its simulation implementation


Supplementary knowledge: functor

A C++ functor (function object) is an object that can be called like a function. A functor is usually a class that overloads the function call operator operator() so that an object can be called.

insert image description here

1. Priority queue:

1. Introduce

Priority Queue (Priority Queue) uses a data structure called heap (Heap) in the underlying implementation, which is usually represented by an array (such as std::vector in C++). A heap is a complete binary tree data structure with the following characteristics:

  1. The heap is a complete binary tree, which means that except for the bottom layer, all other layers must be completely filled, and the nodes at the bottom layer are filled in order from left to right.
    2. The value of each node in the heap is greater than or equal to (or less than or equal to) the value of its child nodes, which is the so-called heap order property.

2. Introduction

  1. A priority queue is a container adapter whose first element is always the largest of its contained elements according to strict weak ordering criteria.
  2. This context is similar to a heap, where elements can be inserted at any time, and only the largest heap element (the one at the top in the priority queue) can be retrieved.
  3. The priority queue is implemented as a container adapter, which encapsulates a specific container class as its underlying container class
  4. The underlying container can be any standard container class template, or any other container class of a specific design. The container should be
    accessible through a random access iterator and support the following operations:
    empty(): check if the container is empty
    size(): return the number of valid elements in the container
    front(): return a reference to the first element in the container
    push_back (): Insert an element at the end of the container
    pop_back(): Delete the element at the end of the container
  5. The standard container classes vector and deque meet these needs. By default, vector is used if no container class is specified for a particular priority_queue class instantiation.

Although vector is used in the underlying implementation, the priority queue still maintains the characteristics of the queue, that is, elements are dequeued according to priority

Second, the simulation implementation of priority_queue

1. General framework

namespace simulation {
    
    
template<class T, class Container = vector<T>, class Compare = less<T>>
	//Compare这里传的是仿函数,默认为系统里自带的less仿函数,也可以自己添加
	//用于比较大小,Container为底层实现容器,默认为vector
	class priority_queue {
    
    

	private://私有成员函数
		void AdjustDown(int parent) {
    
    	 
		}
		void AdjustUp(int child) {
    
    
				 }

	public://公有成员函数
		void pop() {
    
     }
		void push(const T & x) {
    
    }
		const T& top() {
    
     }
		bool empty() {
    
    }
		size_t size() {
    
    }
		priority_queue(){
    
    }

	private:
		Container _con;//成员变量
		 
	};

2. Private member functions:

1. Adjust Down (AdjustDown)

insert image description here
In the picture, a small heap is being built, but our code uses a large heap as an example, except that the directions of greater than and less than are different, but the logic is the same

void AdjustDown(int parent) {
    
    
			//向下调整条件:
	       // 左右子树都是大堆/小堆
			int child = parent * 2 + 1;
			Compare com;//仿函数的实例化
			while (child < _con.size()) {
    
    
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1])) {
    
    
					++child;//选出两个孩子中最大的那一个
				}
				if (com(_con[parent], _con[child])) {
    
    
					//最大的那一个去与父母比较
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else {
    
    
					break;
				}
			}
		}

2. Adjust Up (AdjustUp)

insert image description here
insert image description here

void AdjustUp(int child) {
    
    
			//向上调整条件:
	    // 除了child这个位置前面的数据构成堆
			int parent = (child - 1) / 2;
			Compare com;
			while (child > 0) {
    
    
				if (com(_con[parent], _con[child])) {
    
    
					swap(_con[parent], _con[child]);
					child = parent;
					//接着向上
					parent = (child - 1) / 2;
				}
				else {
    
    
					break;
				}
			}
		}

3. Public member functions

1 size (size).

2 is empty (empty).

3. Remove the element at the top of the heap (pop)

insert image description here

void pop() {
    
    
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

4. Element insertion (push)

insert image description here

void push(const T& x) {
    
    
			_con.push_back(x);
			//新元素向上调整
			AdjustUp(_con.size() - 1);
		}

5. The element at the top of the heap (top)

const T& top() {
    
    
			return _con[0];
		}

6. Constructor

1. Default parameterless construction

priority_queue() {
    
    
//内容可以什么都不写,因为初始化会去内置类型不用管,自定义类型会去调用其
//默认构造函数,这里会直接调用成员变量_con的默认构造
//当你写了迭代器构造后,这个无参构造你必须要有,因为当你写了一个构造函数
//以后,编译器就不会自己再生成默认构造函数
		}

2. Iterator construction

template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last) {
    
    
			while (first != last) {
    
    
				_con.push_back(*first);
				++first;
			}
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {
    
    
				AdjustDown(i);
			}
		}

Guess you like

Origin blog.csdn.net/m0_74774759/article/details/131997047