zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

2014腾讯实习笔试题——优先队列

队列腾讯队列 2014 笔试 优先 实习
2023-09-27 14:27:23 时间

2014腾讯实习笔试题第二题是关于优先队列的。不是非常熟悉,查阅了一下资料。总结一下:

优先队列是基于堆(二叉堆)实现的。每当增加(push)一个新元素时。会依据优先级。将优先级最大(或最小)的元素依照堆排序(大顶堆,小顶堆)的方式放到堆顶。

如此的话。返回的堆顶元素(top)即优先级最高(或最小)的元素。

当然。在pop()操作之后,仍然要进行堆排序,调整元素位置。參考资料例如以下:

1 优先队列

1.1 简单介绍

              队列的特点是先进先出。通常都把队列比喻成排队买东西。大家都非常守秩序。先排队的人就先买东西。

可是优先队列有所不同,它不遵循先进先出的规则,而是依据队列中元素的优先权,优先权最大的先被取出。通常把优先队列比喻成现实生活中的打印。

一个打印店里有非常多打印机,每台机器的性能不一样,有的打印机打印非常快,有的打印机打印速度非常慢。

当这些打印机陆陆续续打印完自己的任务时进入排队等候状态。假设我这个时候要打印一份文件,我选的不是第一个排队的打印机。而是性能最好。打印最快的打印机。

            重点:优先级队列,是要看优先级的,谁的优先级更高,谁就先得到权限。不分排队的顺序!

            基本操作:

                   empty() 假设队列为空返回真

                   pop() 删除对顶元素

                   push() 增加一个元素

                   size() 返回优先队列中拥有的元素个数

                   top() 返回优先队列对顶元素

                   在默认的优先队列中,优先级高的先出队。在默认的int型中先出队的为较大的数。

1.2 用堆实现优先队列

 以下是最小堆实现的优先队列:

#include <iostream>
#include <vector>
using namespace std;

class Heap
{
public:
	Heap(int iSize);
	~Heap();

	int Enqueue(int iVal);
	int Dequeue(int &iVal);
	int GetMin(int &iVal);
	void printQueue();
protected:
	int *m_pData;
	int m_iSize;
	int m_iAmount;
};
Heap::Heap(int iSize = 100)//注意这里是从0開始,所以假设根是i。那么左孩子是2*i+1,右孩子是2*i+2
{
	m_pData = new int[iSize];
	m_iSize = iSize;
	m_iAmount = 0;
}
Heap::~Heap()
{
	delete []m_pData;
}

int Heap::Enqueue(int iVal)//进入堆
{
	if (m_iAmount == m_iSize)
	{
		return 0;
	}
	m_pData[m_iAmount ++] = iVal;
	int iIndex = m_iAmount - 1;
	while (m_pData[iIndex] < m_pData[(iIndex - 1) /2])//上浮,直到满足最小堆
	{
		swap(m_pData[iIndex],m_pData[(iIndex - 1) /2]);
		iIndex = (iIndex - 1) /2;
	}
	return 1;
}

int Heap::Dequeue(int &iVal)//出堆
{
	if (m_iAmount == 0)
	{
		return 0;
	}
	iVal = m_pData[0];//出堆的数据
	m_pData[0] = m_pData[m_iAmount - 1];//最后一个数据放到第一个根上面
	-- m_iAmount;//总数减1
	int rc = m_pData[0];
	int s = 0;
	for (int j = 2*s +1; j < m_iAmount; j *= 2)//最后一个数放到第一个位置以后。開始下沉,来维持堆的性质
	{
		if (j < m_iAmount - 1 && m_pData[j] > m_pData[j+1])
		{
			++ j;
		}
		if (rc < m_pData[j])//rc应该插入在s位置上
		{
			break;
		}
		m_pData[s] = m_pData[j];
		s = j;
	}
	m_pData[s] = rc;
	return 1;
}

int Heap::GetMin(int &iVal)
{
	if (m_iAmount == 0)
	{
		return 0;
	}
	iVal = m_pData[0];
	return 1;
}

void Heap::printQueue()
{
	for (int i = 0; i < m_iAmount; ++ i)
	{
		cout << m_pData[i] << " ";
	}
	cout << endl;
}
int main()
{
	Heap heap;
	heap.Enqueue(4);
	heap.Enqueue(1);
	heap.Enqueue(3);
	heap.Enqueue(2);
	heap.Enqueue(6);
	heap.Enqueue(5);
	heap.printQueue();

	int iVal;
	heap.Dequeue(iVal);
	heap.Dequeue(iVal);

	heap.printQueue();
	return 0;
}

1.3 STL实现优先队列

用法:

头文件:

#include <queue>

声明方式:

1、普通方法:

priority_queue<int>q;
//通过操作,依照元素从大到小的顺序出队

2、自己定义优先级:

  1. struct cmp  
  2. {  
  3.     bool operator()(int x, int y)  
  4.     {  
  5.         return x > y;  
  6.     }  
  7. };  
//当中,第二个參数为容器类型。第三个參数为比較函数。
结构体声明方式:
struct node
{
      int x, y;
       friend bool operator < (node a, node b)
      {
             return a.x > b.x; //结构体中。x小的优先级高
      }
};
priority_queue<node>q;//定义方法
//在该结构中。y为值, x为优先级。


//通过自己定义operator<操作符来比較元素中的优先级。


//在重载”<”时。最好不要重载”>”,可能会发生编译错误

 

2应用

首先优先队列是由堆来实现的,所以以后用到优先队列的地方,能够直接用C++中的STL来直接实现。可是不妨自己实现几次。否则我们仅仅会成为傻瓜,什么东西就知道怎么用,不知道是怎样实现的。

优先队列适用的范围非常广,比方:

1、构造哈夫曼编码

              构造哈夫曼编码是找到节点集合中频率最小的两个点,然后合并节点在插入到集合中,再循环。。

2、一些任务调度算法

            比方操作系统的线程的调度算法,有的是依照优先级来调度的。每次都运行优先级较高的线程

3、合并n个有序文件为一个有序文件

            首先把n个有序文件的第一个元素取出来。放到优先队列里面,然后取最小值,然后再插入元素导优先队列。取最小值。。。

4、因为优先队列内部是有堆实现的。所以适用于堆的都适用于优先队列

          比方排序,找中位数,找最大的k个数


(參考来源:http://blog.csdn.net/zhang20072844/article/details/10286997)