37.队列的概念与实现下

一.静态队列的缺陷

当元素类型为类类型时,静态队列和静态栈有相同的缺点,在创建对象时多次调用其构造函数,影响效率

二.链式栈的实现

2.1 设计要点

  • 抽象父类Queue的直接子类
  • 在内部实现元素的链式存储
  • 只在链表的头部和尾部进行操作

image.png

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;
}
复制代码

结果:

image.png 使用链式队列插入元素时,时间复杂度为O(n),比较低效

三.链式队列的优化

使用双向循环链表实现队列,链表结构移植Linux内核链表,并继承父类队列Queue

image.png

image.png

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),实现高效的插入和删除

猜你喜欢

转载自juejin.im/post/7036753860370628644