您的位置:首页 > 编程语言 > C语言/C++

C++模板链表实现优先级队列

2017-03-25 11:12 597 查看
本文是承接我的上一篇文章,只是将普通队列增加了优先级.实现了一个优先级队列.本文采取的优先级队列的实现方式在于数据增加优先级标志位,在数据进入队列时,根据优先级排序的顺序进入,出队列仍然是从头出.使用该种思想实现的优先级队列.

继承普通链表队列(具体参考http://blog.csdn.net/luanzheng_365/article/details/64518754). 注意需要将普通链表队列的成员变量linkList的访问权限改成protected.

开始时犯了一个错误,在子类中定义
PriorityQueueLinkList<T, capacity> *linkList = NULL;
这样,继承过来的方法isEmpty(), isFull()等中使用的linkList仍是父类的linkList,造成错误.原因是,C++编译器会先构造父类结构,之后再构造子类结构.而继承过来的函数在构造父类的时候就确定了.其并不知道子类的成员变量,因此就无法访问. 总之,这里要注意,继承过来的父类的成员函数(public, protected)在子类中可以使用,但是如果成员函数调用了成员变量,该成员变量也需要在子类中被继承才行(如果成员变量在父类中是privated的就会有问题,子类中从新定义同名成员变量没有任何作用也不可能有任何作用).

对继承来的父类的linkList,在子类中可以使用强制类型转换.将其转换为PriorityQueueLinkList. 这样做是安全的,因为传入的data本来必须要保证是优先级队列中的结点的数据结构.
((PriorityQueueLinkList<T, capacity>*)linkList)->enqueueWithPriority(data);


关键数据结构PriorityQueueLinkList,继承自QueueLinkList. 重新写enque方法.并利用C++的隐藏,将尾插入方法隐藏,因为优先级队列不适用尾插入暴露在外面. 出队列方法则可以直接使用继承自父类的dequeue.

该队列插入的效率有一定问题,在队列超过10000个元素后,插入效率明显降低.后续考虑使用高效的插入算法进行优化比较.

6.补充一点C++继承过程中基类与派生类指针相互强制转换的知识. 如果开始的指针指向父类,之后强制转换成子类的指针,则通过该指针可以操作子类独有的成员函数(包括子类新写的与子类继承后重写/隐藏的). 但如果父类是虚函数,则不管子类是否覆盖,通过该强制转换的指针访问该函数,仍然是访问的父类函数. 如果开始指针指向子类,将其强制转换为父类指针,则子类新写的函数不可见.但被覆盖过的虚函数除外.该指针操作父类的虚函数,会自动调用子类的对应函数(多态).

template<typename T, unsigned int capacity>
class PriorityLinkQueue : public LinkQueue<T, capacity>
{
public:
PriorityLinkQueue();
~PriorityLinkQueue();
bool enQueue(T data);
//private:
//  PriorityQueueLinkList<T, capacity> *linkList = NULL;
};


template <typename T, unsigned int capacity>
PriorityLinkQueue<T, capacity>::PriorityLinkQueue()
{

}

template <typename T, unsigned int capacity>
PriorityLinkQueue<T, capacity>::~PriorityLinkQueue()
{
cout << "PriorityLinkQueue destructor called" << endl;
}

template <typename T, unsigned int capacity>
bool PriorityLinkQueue<T, capacity>::enQueue(T data)
{
/*开始时犯了一个错误,在子类中定义PriorityQueueLinkList<T, capacity> *linkList = NULL;
这样,继承过来的方法isEmpty(), isFull()等中使用的linkList仍是父类的linkList,造成错误.
原因是,C++编译器会先构造父类结构,之后再构造子类结构.而继承过来的函数在构造父类的时候
就确定了.其并不知道子类的成员变量,因此就无法访问.*/
return ((PriorityQueueLinkList<T, capacity>*)linkList)->enqueueWithPriority(data);
}


template <typename T, const unsigned int capacity>
class PriorityQueueLinkList : public QueueLinkList<T, capacity>
{
public:
PriorityQueueLinkList();
~PriorityQueueLinkList();
bool enqueueWithPriority(T data);
private:
bool enqueueAtTail(T data);  //利用C++的隐藏,将尾插入方法隐藏,因为优先级队列不适用尾插入暴露在外面
};


template<typename T, const unsigned int capacity>
PriorityQueueLinkList<T, capacity>::PriorityQueueLinkList()
{

}

template<typename T, const unsigned int capacity>
PriorityQueueLinkList<T, capacity>::~PriorityQueueLinkList()
{
cout << "PriorityQueueLinkList destructor called" << endl;
}

template<typename T, const unsigned int capacity>
bool PriorityQueueLinkList<T, capacity>::enqueueWithPriority(T data)
{
bool rs = false;
if (isFull())
{
rs = false;
}
else
{
if (isEmpty())
{
LinkNode<T> *node = new LinkNode<T>();
node->data = data;
node->next = NULL;
head->next = node;
tail = node;
linkNodeNum++;
rs = true;
}
else
{
LinkNode<T> *iter = head->next;
LinkNode<T> *preIter = head;
while (NULL != iter)
{
unsigned int priority = iter->data.priority;
if (data.priority >= priority)
{
preIter = iter;
iter = iter->next;
}
else
{
//insert after preIter and before iter
LinkNode<T> *node = new LinkNode<T>();
node->data = data;
preIter->next = node;
node->next = iter;
linkNodeNum++;
rs = true;
break;
}
}
if (NULL == iter)
{
rs = enqueueAtTail(data);
}
}
}
return rs;
}

template<typename T, const unsigned int capacity>
bool PriorityQueueLinkList<T, capacity>::enqueueAtTail(T data)
{
return QueueLinkList<T, capacity>::enqueueAtTail(data);     //默认实现,目的在于隐藏该方法
}


测试代码如下:

void testPriorityQueue()
{
PriorityLinkQueue<PriorityQueueNode<int>, 30000> *priorityLinkQueue = new PriorityLinkQueue<PriorityQueueNode<int>, 30000>();

unsigned int num = 0;
while (num<2)
{
num++;
cout << "NUM:" << num << endl;
for (int i = 0; i < 40000; i++)
{
PriorityQueueNode<int> prioQueueNode;
prioQueueNode.priority = (i % 5);
prioQueueNode.data = i;

priorityLinkQueue->enQueue(prioQueueNode);
}

_sleep(2000);

for (int i = 0; i < 35000; i++)
{
PriorityQueueNode<int> deQueueNode;
priorityLinkQueue->deQueue(deQueueNode);
}

_sleep(2000);
}

for (int i = 0; i < 40000; i++)
{
PriorityQueueNode<int> prioQueueNode;
prioQueueNode.priority = (i % 5);
prioQueueNode.data = i;

priorityLinkQueue->enQueue(prioQueueNode);
}

delete priorityLinkQueue;
priorityLinkQueue = NULL;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: