和StaticStack类似,当数据元素为类类型,StaticQueue 的对象在创建时,会多次调用元素类型的构造函数,影响效率。需要实现链式队列。
队列的链式存储实现
设计要点
(1)类模板,抽象父类Queue的直接子类;
(2)在内部使用链式结构实现元素的存储;
(3) 只在链表的头部和尾部进行操作。
LinkQueue实现方式一(使用单链表LinkList)
代码:
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#include "Queue.h"
#include "LinkList.h"
#include "Exception.h"
namespace DTLib
{
template < typename T >
class LinkQueue : public Queue<T>
{
protected:
LinkList<T> m_list;
public:
void add(const T& e) // O(n) 性能不好
{
m_list.insert(e);
}
void remove() // O(1)
{
if (m_list.length() > 0)
{
m_list.remove(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current queue ...");
}
}
T front() const // O(1)
{
if (m_list.length() > 0)
{
return m_list.get(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current queue ...");
}
}
void clear() // O(n)
{
m_list.clear();
}
int length() const // O(1)
{
return m_list.length();
}
};
}
#endif
可以看出这种方式下进队列操作void add(const T& e)需要的时间复杂度是O(n),然而StaticQueue的进队列操作void add(const T& e) 的时间复杂度是O(1)!因为访问数组元素的效率是高于访问链表结点的效率的,有必要采用更好的链式队列实现方案。
LinkQueue实现方式二(使用Linu内核链表)
代码:
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#include "Queue.h"
#include "LinuxList.h"
#include "Exception.h"
namespace DTLib
{
template < typename T >
class LinkQueue : public Queue<T>
{
protected:
struct Node : public Object
{
list_head head;
T value;
};
list_head m_header;
int m_length;
public:
LinkQueue() // O(1)
{
m_length = 0;
INIT_LIST_HEAD(&m_header);
}
void add(const T& e) // O(1)
{
Node* node = new Node();
if (node != NULL)
{
node->value = e;
// O(1)
list_add_tail(&node->head, &m_header);
m_length++;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No memery to add new element ...");
}
}
void remove() // O(1)
{
if (m_length > 0)
{
list_head* toDel = m_header.next; // 队头元素所在的位置
list_del(toDel);
m_length--;
delete list_entry(toDel, Node, head);
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current queue ...");
}
}
T front() const // O(1)
{
if (m_length > 0) // 返回队头数据的值,即头结点next指针所指向的值
{
return list_entry(m_header.next, Node, head)->value;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No element in current queue ...");
}
}
void clear() // O(n)
{
while (m_length > 0)
{
remove();
}
}
int length() const // O(1)
{
return m_length;
}
~LinkQueue() // O(n)
{
clear();
}
};
}
#endif
功能测试
#include <iostream>
#include "StaticQueue.h"
#include "LinkQueue.h"
using namespace std;
using namespace DTLib;
int main(void)
{
LinkQueue<int> queue;
for (int i = 0; i < 10; i++)
{
queue.add(i);
}
while (queue.length()>0)
{
cout << queue.front() << endl;
queue.remove();
}
return 0;
}
输出结果符合队列的先进先出的特性。
0
1
2
3
4
5
6
7
8
9
请按任意键继续. . .
小结
(1)StaticQueue 在初始化时可能多次调用元素类型的构造函数;
(2)Linklist 的组合使用能够实现队列的功能,但是不够高效;
(3)LinkQueue 的最终实现组合使用了 Linux 内核链表;
(4)LinkQueue 中入队和出队操作可以在常量时间内完成。