一.静态队列的缺陷
当元素类型为类类型时,静态队列和静态栈有相同的缺点,在创建对象时多次调用其构造函数,影响效率
二.链式栈的实现
2.1 设计要点
- 抽象父类Queue的直接子类
- 在内部实现元素的链式存储
- 只在链表的头部和尾部进行操作
2.2 链式队列的结构设计
#include <iostream>
#include "Queue.h"
#include "LinkList.h"
template<typename T>
class linkQueue :public Queue<T>
{
public:
LinkList<T> m_list;
};
复制代码
2.3 插入
单链表的尾插法,时间复杂度为O(n)
void add(const T& e)
{
//链表的尾部插法
m_list.insert(e);
}
复制代码
2.4 移除
单链表的头部移除,时间复杂度为O(1)
void remove()
{
//头部移除
if (m_list.length() > 0)
{
m_list.remove(0);
}
else
{
cout << "no elem to remove" << endl;
}
}
复制代码
2.4 获取队列元素/清空/长度/析构函数
//获取头部元素,0表示头结点,不带数据
T front() const
{
if (m_list.length() > 0)
{
return m_list.get(0);
}
else
{
cout << "no elem to get" << endl;
}
}
void clear()
{
if (m_list.length() > 0)
{
m_list.clear();
}
else
{
cout << "no elem to clear" << endl;
}
}
int size()
{
return m_list.length();
}
~linkQueue()
{
clear();
}
复制代码
2.5 完整代码
linkQueue.h
#pragma once
#include <iostream>
#include "Queue.h"
#include "LinkList.h"
using namespace std;
template<typename T>
class linkQueue :public Queue<T>
{
public:
LinkList<T> m_list;
linkQueue()
{
}
void add(const T& e)
{
//链表的尾部插法
m_list.insert(e);
}
void remove()
{
//头部移除
if (m_list.length() > 0)
{
m_list.remove(0);
}
else
{
cout << "no elem to remove" << endl;
}
}
//获取头部元素,0表示头结点,不带数据
T front() const
{
if (m_list.length() > 0)
{
return m_list.get(0);
}
else
{
cout << "no elem to get" << endl;
}
}
void clear()
{
if (m_list.length() > 0)
{
m_list.clear();
}
else
{
cout << "no elem to clear" << endl;
}
}
int size()
{
return m_list.length();
}
~linkQueue()
{
cout << "~linkQueue" << endl;
clear();
}
};
复制代码
测试程序
linkQueue.cpp
#include <iostream>
#include "linkQueue.h"
int main()
{
linkQueue<int> queue;
for (int i = 0; i < 5; i++)
{
queue.add(i);
}
for (int i = 0; i < 5; i++)
{
cout << queue.front() << endl;
queue.remove();
}
return 0;
}
复制代码
结果:
使用链式队列插入元素时,时间复杂度为O(n),比较低效
三.链式队列的优化
使用双向循环链表实现队列,链表结构移植Linux内核链表,并继承父类队列Queue
3.1 完整代码
DualLinkQueue.h
#pragma once
#include <iostream>
#include "Queue.h"
#include "LinuxList.h"
using namespace std;
template<typename T>
class DualLinkQueue : public Queue<T>
{
protected:
struct Node
{
list_head head;
T e;
};
list_head m_head;
int m_length;
public:
DualLinkQueue()
{
m_length = 0;
INIT_LIST_HEAD(&m_head);
}
void add(const T& e)//O(1)
{
struct Node* node = new Node();
if (node)
{
node->e = e;
list_add_tail(&node->head, &m_head);
m_length++;
}
else
{
cout << "no mem to new" << endl;
}
}
void remove()//O(1)
{
if (m_length > 0)
{
list_head* toDel = m_head.next;
list_del(toDel);
delete list_entry(toDel, struct Node, head);
m_length--;
}
}
//获取头部元素,0表示头结点,不带数据
T front() const
{
if (m_length > 0)
{
list_head* toFind = m_head.next;
return list_entry(toFind, struct Node, head)->e;
}
else
{
cout << "no elem to get" << endl;
}
}
void clear()
{
while (m_length > 0)
{
remove();
}
}
int size()
{
return m_length;
}
~DualLinkQueue()
{
clear();
}
};
复制代码
测试程序和结果和前面相同
四.小结
- staticQueue在构造时可能会多次调用对象的构造函数
- linkQueue组合了链表的特性实现队列的功能,但是不够高效
- DualLinkQueue集合Linux内核链表的特性实现队列,队列的出队和入队时间复杂度都是O(1),实现高效的插入和删除