数据结构——队列

简介:

1 队列是一种只允许在表的一端插入元素,在另一端删除元素的特殊的线性表。允许插入的一端成为队尾(rear),允许删除的一端成为队头(front)。当队列中没有任何元素时成为空队列。队列是一种先进先出的线性表,简称FIFO表。

2 与栈类似,队列也是一种操作受限的特殊的线性表,同样可以采用顺序存储结构和链式存储结构来表示队列。

3 队列的顺序存储表示——循环队列

队列的顺序存储表示同样是利用一维数组来实现。为了解决“假溢出”问题,可以将队列的数组看成是头尾相接的环状空间,当队尾元素放到数组的最后一个位置时,如需入队就把新元素接着存放在数组的0下表位置,这样的队列成为循环队列。循环队列的基本操作的实现如下:

#ifndef _SQQUEUE_
#define _SQQUEUE_
template<class T>
class SqQueue
{
public:
	SqQueue(int m = 100);
	~SqQueue();
	void Clear();
	bool Empty() const;
	int Length() const;
	T& GetHead() const;
	T& GetLast() const;
	void Append(const T&);
	void Remove();
private:
	T* m_base;
	int m_front;
	int m_rear;
	int m_size;
};

template<class T> SqQueue<T>::SqQueue(int m)
{
	m_front = m_rear = 0;
	m_size = m;
	m_base = new T[m];
}

template<class T> SqQueue<T>::~SqQueue()
{
	delete [] m_base;
}

template<class T> void SqQueue<T>::Clear()
{
	m_front = m_rear = 0;
}

template<class T> bool SqQueue<T>::Empty() const
{
	return m_front == m_rear;
}

template<class T> int SqQueue<T>::Length() const
{
	return (m_rear - m_front + m_size) % m_size;
}

template<class T> T& SqQueue<T>::GetHead() const
{
	if (!Empty())
	{
		return m_base[m_front];
	}
}

template<class T> T& SqQueue<T>::GetLast() const
{
	if (!Empty())
	{
		return m_base[(m_rear - 1 + m_size) % m_size];
	}
}

template<class T> void SqQueue<T>::Append(const T& e)
{
	int i,j;
	if (m_front == (m_rear + 1) % m_size)
	{
		T* newbase = new T[m_size + 10];
		for (i = m_front,j = 0; i < m_rear; i = (i + 1) % m_size, j++)
		{
			newbase[j] = m_base[i];
		}
		delete [] m_base;
		m_base = newbase;
		m_front = 0;
		m_rear = j;
		m_size += 10;
	}
	m_base[m_rear] = e;
	m_rear = (m_rear + 1) % m_size;
}

template<class T> void SqQueue<T>::Remove()
{
	if (!Empty())
	{
		m_front = (m_front + 1) % m_size;
	}
}
#endif

在循环队列中,上述基本操作的时间复杂度均为O(1)。

4 队列的链式存储表示——链队列

#ifndef _LINKQUEUE_
#define _LINKQUEUE_
template<class T>
class LinkQueue
{
public:
	LinkQueue();
	~LinkQueue();
	void Clear();
	bool Empty() const;
	int Length() const;
	T* GetHead() const;
	T* GetLast() const;
	void Append(const T&);
	void Remove();
private:
	LinkNode<T>* m_front;
	LinkNode<T>* m_rear;
};

template<class T> LinkQueue<T>::LinkQueue()
{
	m_front = m_rear = new LinkNode<T>;
	m_front->next = NULL;
}

template<class T> LinkQueue<T>::~LinkQueue()
{
	Clear();
	delete m_front;
}

template<class T> void LinkQueue<T>::Clear()
{
	LinkNode<T>* p;
	while (m_front->next != NULL)
	{
		p = m_front->next;
		m_front->next = p->next;
		delete p;
	}
	m_rear = m_front;
}

template<class T> bool LinkQueue<T>::Empty() const
{
	return m_front == m_rear;
}

template<class T> int LinkQueue<T>::Length() const
{
	int i = 0;
	LinkNode<T>* p = m_front;
	while (p->next != NULL)
	{
		i++;
		p = p->next;
	}
	return i;
}

template<class T> T& LinkQueue<T>::GetHead() const
{
	while(!Empty())
	{
		return m_front->next->data;
	}
}

template<class T> T& LinkQueue<T>::GetLast() const
{
	while(!Empty())
	{
		return m_rear->data;
	}
}

template<class T> void LinkQueue<T>::Append(const T& e)
{
	LinkNode<T>* p = new LinkNode<T>;
	p->data = e;
	p->next = NULL;
	m_rear->next = p;
	m_rear = p;
}

template<class T> void LinkQueue<T>::Remove()
{
	LinkNode<T>* p;
	if (!Empty())
	{
		p = m_front->next;
		m_front->next = p->next;
		if (p == m_rear)
		{
			m_rear = m_front;
		}
		delete p;
	}
}
#endif
链队列的队空条件为front = rear,或者front->next = NULL,而队满只在内不能无可用空间时才发生,所以链队列特别适合于队列元素个数变化比较大的情况。
在链队列的操作中,队列的销毁、清空和求长度操作的时间复杂度为O(n),因为需要对链表的每个结点进行处理。队列的其余操作的时间复杂度为O(1)。
5 队列的应用
5.1 舞伴问题
假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题。
#include <iostream>
#include <fstream>
#include "SqQueue.h"
using namespace std;

struct Dancer
{
	char name[20];
	char sex;
};

void main(int argc, char* argv[])
{
	ifstream input("input.txt");
	SqQueue<Dancer> M(50), F(50);
	Dancer d;
	input>>d.name>>d.sex;
	while (d.sex != '#')
	{
		if (d.sex == 'M' || d.sex == 'm')
		{
			M.Append(d);
		}
		else if (d.sex == 'F' || d.sex == 'f')
		{
			F.Append(d);
		}
		input>>d.name>>d.sex;
	}

	while (!M.Empty() && !F.Empty())
	{
		Dancer d = M.GetHead();
		M.Remove();
		cout<<d.name<<" ";
		Dancer d2 = F.GetHead();
		F.Remove();
		cout<<d2.name<<endl;
	}

	if (!M.Empty())
	{
		cout<<"依然还有"<<M.Length()<<"男舞者在等待"<<endl;
		cout<<M.GetHead().name<<"最先获得舞伴"<<endl;
	}
	else if (!F.Empty())
	{
		cout<<"依然还有"<<F.Length()<<"女舞者在等待"<<endl;
		cout<<F.GetHead().name<<"最先获得舞伴"<<endl;
	}
	else
	{
		cout<<"没有等待的舞者!"<<endl;
	}
	system("pause");
}

5.2 火车车厢重排问题
一列货运列车共有 n 节车厢,每节车厢将停放在不同的车站。假定 n 个车站的编号分别为 1 ~ n ,即货运列车按照第 n 站至第 1 站的次序经过这些车站。为了便于从列车上卸掉相应的车厢,车厢的编号应与车站的编号相同,这样,在每个车站只需卸掉最后一节车厢。所以,给定任意次序的车厢,必须重新排列他们。
车厢的重排工作可以通过转轨站完成。在转轨站中有一个入轨、一个出轨和 k 个缓冲轨,缓冲轨位于入轨和出轨之间。假定 缓冲轨按先进先出的方式运作,设计算法解决火车车厢重排问题。
TrackStation.h

#include "SqQueue.h"
#pragma once
class CTrackStation
{
public:
	CTrackStation(int trackCount);
	~CTrackStation(void);
	bool Realign(int* A, int n);
private:
	bool HoldIn(int car);
	bool HoldOut(int car);

	SqQueue<int>* m_pTracks;
	int m_trackCount;
};

 
TrackStation.cpp<pre name="code" class="cpp">#include "TrackStation.h"
#include <iostream>

CTrackStation::CTrackStation(int trackCount):m_trackCount(trackCount)
{
	m_pTracks = new SqQueue<int>[m_trackCount];
}


CTrackStation::~CTrackStation(void)
{
	delete [] m_pTracks;
}

bool CTrackStation::HoldIn(int car)
{
	int bestTrack = -1;
	int bestLast = -1;
	int i;
	for (i = 0; i < m_trackCount; i++)
	{
		if (!m_pTracks[i].Empty())
		{
			int last = m_pTracks[i].GetLast();
			if (car > last && last > bestLast)
			{
				bestTrack = i;
				bestLast = last;
			}
		}
	}

	if (bestTrack == -1)
	{
		for (i = 0; i < m_trackCount; i++)
		{
			if (m_pTracks[i].Empty())
			{
				bestTrack = i;
				break;
			}
		}
	}

	if (bestTrack == -1)
	{
		return false;
	}
	m_pTracks[bestTrack].Append(car);
	std::cout<<car<<"号车厢进入"<<bestTrack<<"号缓冲轨"<<std::endl;
	return true;
}

bool CTrackStation::HoldOut(int car)
{
	for (int i = 0; i < m_trackCount; i++)
	{
		if (!m_pTracks[i].Empty())
		{
			int headCar = m_pTracks[i].GetHead();
			if (headCar == car)
			{
				headCar =m_pTracks[i].GetHead();
				m_pTracks[i].Remove();
				std::cout<<headCar<<"号车厢从"<<i<<"号缓冲轨出站"<<std::endl;
				return true;
			}
		}
	}
	return false;
}

bool CTrackStation::Realign(int* A, int n)
{
	int nowOut = 1, i = 0;
	while (nowOut <= n)
	{
		if (HoldOut(nowOut))
		{
			nowOut++;
			continue;
		}
		if (i >= n || !HoldIn(A[i]))
		{
			return false;
		}
		i++;
	}
	return true;
}


 
Main.cpp<pre name="code" class="cpp">#include <iostream>
#include <fstream>
#include "TrackStation.h"
using namespace std;

void main(int argc, char* argv[])
{
	int k;
	cout<<"请输入缓冲轨数目:";
	ifstream input("input.txt");
	input>>k;
	CTrackStation trackStation(k);
	cout<<"请依次输入入轨的车厢次序,以0结束:";
	int car, n = 0, A[100];
	input>>car;
	while(car > 0 && n < 100)
	{
		A[n++] = car;
		input>>car;
	}
	if (!trackStation.Realign(A,n))
	{
		cout<<"车厢无法重排!"<<endl;
	}
	system("pause");
}


转载:http://blog.csdn.net/foreverling/article/details/43153389

目录
相关文章
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
289 9
|
14天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
132 77
|
3月前
|
缓存 算法 调度
数据结构之 - 双端队列数据结构详解: 从基础到实现
数据结构之 - 双端队列数据结构详解: 从基础到实现
136 5
|
14天前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
36 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
14天前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
38 9
|
14天前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
30 7
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
89 5
|
2月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
3月前
初步认识栈和队列
初步认识栈和队列
69 10
|
3月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
39 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列

热门文章

最新文章