用类模板设计一个队列(选用数组或链表),解决n个人围成一圈的问题

1. 用栈(数组)实现
思想:
因为数组是一维的,头尾不相连,所以考虑使用两个整型变量记录队列的头和尾在数组中的下标(也就是pop和push的位置),通过对数组长度取余的方式从数组的头跳到尾,实现头尾相连(围成一圈)。

文字很难描述,可以在脑海中想象一下,有点像是火车在围成一圈的轨道上跑的感觉,火车是队列,轨道是数组。比如长度为10的数组(下标0到9),pop或者push的下标从9增加到10时,通过对10取余回到下标为0的位置。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;

template<typename T>
class Queue {
public:
	Queue(int size) {
		MAX_SIZE = size;
		tp = new T[size];
		this->size = 0;
		this->p_pop = 0;     //队列从下标0开始pop出数据,所以初始化为0
		this->p_push = -1;    //队列从下标0开始push数据,所以初始化为-1
	}
	~Queue() {
		delete tp;
	}
	void push(T dat) {
		if (this->size == MAX_SIZE) {
			printf("stack is overflow!\n");
			return;
		}
		p_push++;
		p_push %= MAX_SIZE;     //push入数据到数组的末尾时,通过取余跳到数组的开头,实现循环和重复利用地址
		tp[p_push] = dat;
		size++;
	}
	T pop() {
		if (size == 0) {
			printf("stack is empty!\n");
			exit(1);
		}
		T temp = tp[p_pop++];
		p_pop %= MAX_SIZE;    //pop出数据到数组的末尾时,通过取余跳到数组的
		size--;
		return temp;
	}
	int getSize() {
		return size;
	}
	void travel() {
		int len = size;
		int p = p_pop;
		printf(":==================================\n");
		printf("size=%d\t", size);
		printf("p_pop=%d, p_push=%d\n", p_pop, p_push);
//		while (p != p_push + 1) {    //用下标判断队列为空
//			printf("%d ", tp[p]);
//			p++;
//			p %= MAX_SIZE;
//		}
		while (len--) {//用队列长度判断队列为空
			printf("%d ", tp[p]);
			p++;
			p %= MAX_SIZE;
		}
		printf("\n==================================;\n");
	}
private:
	int size;    //队列的长度
	int MAX_SIZE;   //队列长度上限,也就是数组的长度,通过构造函数初始化
	T* tp;
	int p_pop;     //记录pop的位置,也就是队列的头
	int p_push;     //记录push的位置,也就是队列的尾
};

int main() {
	Queue<int> queue(30);
	queue.travel();      //打印空表验证

    //报三减一的游戏来验证
	for (int i = 1; i <= 13; i++) {序号为1~13的人围成一圈队列
		queue.push(i);
	}
	queue.travel();

	int count = 0;         //报数的记录,报到3的倍数的人被淘汰
	while (queue.getSize()) {
		count++;
		int temp = queue.pop();    //报数的人被pop出来
		if (count % 3 == 0) {     //如果是3的倍数直接淘汰,不push回队列。
			printf("%d\n", temp);
		} else {                  //不是3的倍数的成员push回队列,接着后面的游戏
			queue.push(temp);
		}
	}
	queue.travel();//打印空表验证

	return 0;
}

运行结果(Eclipse):
在这里插入图片描述

2. 用链表实现
思想:
类(List)模板内创建结构体(即每一个成员),结构体内存放数据data和尾指针next(指向下一个成员从而实现循环一圈)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

template<class T>
class Link {
public:

	Link() :
			head(0), tail(0), LinkSize(0) {
	}
	~Link() {
		Clear();
	}
	bool is_Empty();
	int getSize();

	void Push(const T&);
	void Pop();
	void show();
	void Clear();
	T& getHead() {    //其实可以和Pop函数合并成一个函数,带有返回值T的Pop函数
		return head->data;
	}

private:
	struct Node {
		T data;
		//Node* prev;
		Node* next;
		Node(const T& data, Node* next = NULL) :
				data(data), next(next) {
		}
		;
	};
	Node* head, *tail;
	int LinkSize;
};

template<class T>
inline int Link<T>::getSize() {
	return LinkSize;
}
template<class T>
inline bool Link<T>::is_Empty() {
	return head == NULL;
}
template<class T>
inline void Link<T>::Push(const T& data) {
	if (is_Empty()) {
		head = new Node(data);
		tail = head;
	} else {
		tail->next = new Node(data);
		tail = tail->next;
	}
	LinkSize++;
}
template<class T>
inline void Link<T>::Pop() {
	Node* temp = head;
	head = head->next;
	delete temp;
	LinkSize--;
}
template<class T>
inline void Link<T>::Clear() {
	while (!is_Empty()) {
		Pop();
	}
}
template<class T>
inline void Link<T>::show() {
	Node* lp = head;
	for (int i = 0; i < LinkSize; i++) {
		cout << lp->data << "\t";
		lp = lp->next;
	}
	cout << endl;
	cout << endl;
}
int main() {
	int i , j;

	Link<int> link1;
	for (i = 1; i <= 9; i++) {
		link1.Push(i);
	}
	link1.show();
	i = 0;
	while (!link1.is_Empty()) {
		i++;
		j = link1.getHead();
		if (i % 3 != 0) {
			link1.Push(j);
		}
		link1.Pop();
		if (i % 3 == 0) {
			cout << j << " is out!" << endl;
			link1.show();
		}
	}
	return 0;
}

运行结果(Eclipse):
在这里插入图片描述

========================================================
【文章为本人的学习笔记部分的分享,有任何错误地方欢迎评论指出,万分感谢!】

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值