顺序队列的问题
当数据元素为类类型,StaticQueue 的对象在创建时会多次调用元素类型的构造函数,影响效率!
文件:main.cpp
#include
#include "StaticQueue.h"
using namespace std;
using namespace DTLib;
class Test : public Object
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
StaticQueue queue;
cout << "queue.length() = " << queue.length() << endl;
return 0;
}
输出:
Test()
Test()
Test()
Test()
Test()
queue.length() = 0
~Test()
~Test()
~Test()
~Test()
~Test()
队列的链式存储实现
链式队列的设计要点
类模板,抽象父类 Queue 的直接子类
在内部使用链式结构实现元素的存储
只在链表的头部和尾部进行操作
编程实验:基于 LinkList 的队列
文件:LinkQueue.h
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include "Queue.h"
#include "LinkList.h"
#include "Exception.h"
namespace DTLib
{
template
class LinkQueue : public Queue
{
public:
LinkQueue() = default;
void add(const T &e) override // O(n)
{
m_list.insert(e);
}
void remove() override // O(1)
{
if (m_list.length() > 0)
{
m_list.remove(0);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current StaticQueue ...");
}
}
T front() const override // O(1)
{
if (m_list.length() > 0)
{
return m_list.get(0);
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current StaticQueue ...");
}
}
void clear() override // O(n)
{
m_list.clear();
}
int length() const override // O(1)
{
return m_list.length();
}
~LinkQueue() // O(n)
{
clear();
}
protected:
LinkList m_list;
};
}
#endif // LINKQUEUE_H
文件:main.cpp
#include
#include "LinkQueue.h"
using namespace std;
using namespace DTLib;
class Test : public Object
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
LinkQueue queue_t;
cout << "-----" << endl;
LinkQueue queue;
for (int i=0; i<5; ++i)
{
queue.add(i);
}
while (queue.length() > 0)
{
cout << queue.front() << endl;
queue.remove();
}
return 0;
}
输出:
-----
0
1
2
3
4
问题:使用 LinkList 类实现链表式队列是否合适?是否有更好的方案?
void add(const T &e) override // O(n)
{
m_list.insert(e);
}
每次插入新元素,都需要遍历整个链表到尾部!!
链式存储实现的优化
编程实验:基于 Linux 内核链表的队列
文件:LinkQueue.h
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include "Queue.h"
#include "LinuxList.h"
#include "Exception.h"
namespace DTLib
{
template
class LinkQueue : public Queue
{
public:
LinkQueue()
{
m_length = 0;
INIT_LIST_HEAD(&m_header);
}
void add(const T &e) override // O(1)
{
Node *node = new Node;
if (node != nullptr)
{
node->value = e;
list_add_tail(&node->head, &m_header);
++m_length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to add element ...");
}
}
void remove() override // 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(InvalidOpertionExcetion, "No element in current LinkQueue ...");
}
}
T front() const override // O(1)
{
if (m_length > 0)
{
return list_entry(m_header.next, Node, head)->value;
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current LinkQueue ...");
}
}
void clear() override // O(n)
{
while (m_length > 0)
{
remove();
}
}
int length() const override // O(1)
{
return m_length;
}
~LinkQueue() // O(n)
{
clear();
}
protected:
struct Node : public Object
{
list_head head;
T value;
};
list_head m_header;
int m_length;
};
}
#endif // LINKQUEUE_H
文件:main.cpp
#include
#include "LinkQueue.h"
using namespace std;
using namespace DTLib;
class Test : public Object
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
LinkQueue queue_t;
cout << "-----" << endl;
LinkQueue queue;
for (int i=0; i<5; ++i)
{
queue.add(i);
}
while (queue.length() > 0)
{
cout << queue.front() << endl;
queue.remove();
}
return 0;
}
输出:
-----
0
1
2
3
4
小结
SaticQueue 在初始化时可能多次调用元素类型的构造函数
LinkList 的组合使用实现了队列的功能,但是不够高效
LinkQueue 的最终实现组合使用了 Linux 内核链表
LinkQueue 中入队和出队操作可以在常量时间内完成
以上内容整理于狄泰软件学院系列课程,请大家保护原创!