数据结构 循环队列及应用(泛型编程)

数据结构 循环队列及应用(泛型编程)循环队列特点:先进先出(FIFO)队头队尾指针只向后移动入队时队尾指针后移,出队时队头指针后移当队头指针与队尾指针相等时即为队空当(Q.rear+1)%MAX_Q_SIZE==Q.front时即为队满定义:templa

循环队列

特点:

  1. 先进先出(FIFO)
  2. 队头队尾指针只向后移动
  3. 入队时队尾指针后移,出队时队头指针后移
  4. 当队头指针与队尾指针相等时即为队空
  5. 当(Q.rear + 1) % MAX_Q_SIZE == Q.front时即为队满

定义:

template<typename QElemType>
struct SqQueue
{ 
   
	QElemType qet[MAX_Q_SIZE];
	int front, rear;
};

基本操作:

template<typename QElemType>
Status initSqQueue(SqQueue<QElemType>& Q)//初始化
//队头队尾指针置0
{ 
   
	Q.rear = 0;
	Q.front = 0;
	return OK;
}

template<typename QElemType>
bool isSqQueueEmpty(SqQueue<QElemType>& Q)//判断队空
//队头指针于队尾指针相等
{ 
   
	return Q.rear == Q.front;
}

template<typename QElemType>
bool isSqQueueFull(SqQueue<QElemType>& Q)//判断队满
{ 
   
	return (Q.rear + 1) % MAX_Q_SIZE == Q.front;
}

template<typename QElemType>
Status enSqQueue(SqQueue<QElemType>& Q, QElemType qe)//入队 qe为要入队的数据
//将e赋值给队尾指针位置的元素,队尾指针后移,要注意循环队列后移都需要进行加1取余操作
{ 
   
	if (isSqQueueFull(Q))//队满
	{ 
   
		cout << "队满" << endl;
		return ERROR;
	}//未满
	Q.qet[Q.rear] = qe;
	Q.rear = (Q.rear + 1) % MAX_Q_SIZE;
	return OK;
}

template<typename QElemType>
Status deSqQueue(SqQueue<QElemType>& Q, QElemType& qe)//出队 qe用来接受出队的元素
//将队头指针位置的元素赋值给qe,队头指针后移,此时qe必须时引用才能正确接收到数据
{ 
   
	if (isSqQueueEmpty(Q))//队空
	{ 
   
		cout << "队空" << endl;
		return ERROR;
	}//不空
	qe = Q.qet[Q.front];
	Q.front = (Q.front + 1) % MAX_Q_SIZE;
	return OK;
}

template<typename QElemType>
int getSqQueueLength(SqQueue<QElemType>& Q)//获取队列实际长度
{ 
   
	return ((Q.rear - Q.front) + MAX_Q_SIZE) % MAX_Q_SIZE;
}

template<typename QElemType>
Status getSqQueueFront(SqQueue<QElemType>& Q, QElemType& qe)//获取队头元素 qe用于接收队头元素
//将队头指针位置的元素赋值给qe,qe必须时引用
{ 
   
	if (isSqQueueEmpty(Q))//队空
	{ 
   
		cout << "队空" << endl;
		return ERROR;
	}//不空
	qe = Q.qet[Q.front];
	return OK;
}

template<typename QElemType>
Status clearSqQueue(SqQueue<QElemType>& Q)//清空队列
//队头队尾指针置0
{ 
   
	Q.rear = 0;
	Q.front = 0;
	return OK;
}

template<typename QElemType>
ostream& operator<<(ostream& os, SqQueue<QElemType>& Q)//运算符重载 按线性表格式输出
//按线性表格式输出元素,即 (a1, a2, a3, ……, an) 的格式
{ 
   
	if (isSqQueueEmpty(Q))//队空
	{ 
   
		os << "队空";
		return os;
	}
	os << "(";
	for (int i = Q.front; i != Q.rear; i = (i + 1) % MAX_Q_SIZE)//注意i的变化与指针相同,需要进行取余操作
	{ 
   
		os << Q.qet[i] << ", ";
	}
	os << "\b\b)";//注意删除最后一个元素的逗号
	return os;
}

测试:

void testSqQueue()//测试队列功能
{ 
   
	int i;
	typedef int QElemType;
	QElemType qe;
	SqQueue<QElemType> Q;
	initSqQueue(Q);
	cout << "测试开始……" << endl;
	cout << "初始化完成……" << endl;
	cout << "当前队列为:" << Q << " 队列长度为:" << getSqQueueLength(Q) << endl;
	
	cout << endl << "0~4入队……" << endl;
	for (i = 0; i < 5; i++)
	{ 
   
		enSqQueue(Q, i);
	}
	cout << "当前队列为:" << Q << " 队列长度为:" << getSqQueueLength(Q);
	getSqQueueFront(Q, qe);
	cout << " 队头元素为:" << qe << endl;

	cout << endl << "出队3个元素……" << endl;
	for (int j = 0; j < 3; j++)
	{ 
   
		deSqQueue(Q, qe);
	}
	cout << "当前队列为:" << Q << " 队列长度为:" << getSqQueueLength(Q);
	getSqQueueFront(Q, qe);
	cout << " 队头元素为:" << qe << endl;

	cout << endl << "5~9入队……" << endl;
	for (; i < 10; i++)
	{ 
   
		enSqQueue(Q, i);
	}
	cout << "当前队列为:" << Q << " 队列长度为:" << getSqQueueLength(Q);
	getSqQueueFront(Q, qe);
	cout << " 队头元素为:" << qe << endl;

	cout << endl << "10~14入队……" << endl;
	for (; i < 15; i++)
	{ 
   
		enSqQueue(Q, i);
	}
	cout << "当前队列为:" << Q << " 队列长度为:" << getSqQueueLength(Q);
	getSqQueueFront(Q, qe);
	cout << " 队头元素为:" << qe << endl;
	cout << "测试结束……" << endl;

	system("pause");
}

在这里插入图片描述

队列的应用——凯撒加密:
输入明文和密钥,分别依次读取一个明文和密钥,将明文的字母按字母表顺序向后移动密钥在字母表中的位置,若超出字母表,则继续从头开始后移,将当前密钥出队再重新入队,便于密钥重复利用

//头文件
#pragma once
#include<iostream>
#include"SqQueue.h"
using namespace std;

const int maxKeyLength = 9;
const int maxArrayLength = 1000;

void enterKey(char* key, int& keyLength);//输入密钥 key用于保存密钥,keyLength用于保存密钥长度
void enterMessage(char* message, int& messageLength);//输入消息 message用于保存消息,messageLength用于保存消息长度
void keyEnSqQueue(SqQueue<char>& keyQ, char* key, int keyLength);//将密钥入队 便于多次使用,提高简洁性
void cesarEncode(SqQueue<char> keyQ, char* message, int messageLength, char* ciphertext);//加密 密钥队列,消息,消息长度,存放密文
void cesarDecode(SqQueue<char> keyQ, char* ciphertext, int ciphertextLength, char* cleartext);//解密 密钥队列,密文,密文长度,存放解密结果
void cesar();
//实现
#include<iostream>
#include"SqQueue.h"
#include"Cesar.h"
using namespace std;

void enterKey(char* key, int& keyLength)//输入密钥 key用于保存密钥,keyLength用于保存密钥长度
{ 
   
	char c;
	keyLength = 0;
	cout << "输入密钥:" << endl;
	c = getchar();//吃掉上一个操作的回车
	c = getchar();
	while (c != '\n')
	{ 
   
		if (c <= 'z' && c >= 'a')
		{ 
   
			c = c - 'a' + 'A';//将所有字母转换为大写
		}
		key[keyLength++] = c;
		c = getchar();
	}
	key[keyLength] = '\0';
}

void enterMessage(char* message, int& messageLength)//输入消息 message用于保存消息,messageLength用于保存消息长度
{ 
   
	char c;
	messageLength = 0;
	cout << "输入消息:" << endl;
	c = getchar();
	while (c != '\n')
	{ 
   
		if (c <= 'z' && c >= 'a')
		{ 
   
			c = c - 'a' + 'A';//将所有字母转换为大写
		}
		message[messageLength++] = c;
		c = getchar();
	}
	message[messageLength] = '\0';
}

void keyEnSqQueue(SqQueue<char>& keyQ, char* key, int keyLength)//将密钥入队 便于多次使用,提高简洁性
{ 
   
	for (int i = 0; i < keyLength; i++)
		enSqQueue(keyQ, key[i]);
}

void cesarEncode(SqQueue<char> keyQ, char* message, int messageLength, char* ciphertext)//加密 密钥队列,消息,消息长度,存放密文
{ 
   
	for (int i = 0; i < messageLength; i++)
	{ 
   
		if (message[i] > 'Z' || message[i] < 'A')
		{ 
   
			ciphertext[i] = message[i];//非字母不加密
		}
		else
		{ 
   
			char keychar;
			deSqQueue(keyQ, keychar);
			ciphertext[i] = ((message[i] - 'A') + (keychar - 'A')) % 26 + 'A';//取余操作使超出Z后重新从A开始循环,并提高简洁性
			enSqQueue(keyQ, keychar);//入队使密钥可以复用
		}
	}
	ciphertext[messageLength] = '\0';
}

void cesarDecode(SqQueue<char> keyQ, char* ciphertext, int ciphertextLength, char* cleartext)//解密 密钥队列,密文,密文长度,存放解密结果
{ 
   
	for (int i = 0; i < ciphertextLength; i++)
	{ 
   
		if (ciphertext[i] > 'Z' || ciphertext[i] < 'A')
		{ 
   
			cleartext[i] = ciphertext[i];//非字母无需解密
		}
		else
		{ 
   
			char keychar;
			deSqQueue(keyQ, keychar);
			cleartext[i] = (((ciphertext[i] - 'A') - (keychar - 'A')) + 26) % 26 + 'A';//取余操作使小于A后重新从Z开始循环,并提高简洁性
			enSqQueue(keyQ, keychar);//入队使密钥可以复用
		}
	}
	cleartext[ciphertextLength] = '\0';
}

void cesar()
{ 
   
	char key[maxKeyLength];
	char message[maxArrayLength];
	char ciphertext[maxArrayLength];
	char cleartext[maxArrayLength];
	int keyLength;
	int messageLength;
	SqQueue<char> keyQ;
	initSqQueue(keyQ);

	enterKey(key, keyLength);
	keyEnSqQueue(keyQ, key, keyLength);
	enterMessage(message, messageLength);
	cesarEncode(keyQ, message, messageLength, ciphertext);
	cesarDecode(keyQ, ciphertext, messageLength, cleartext);//ciphertextLength == messageLength
	cout << "明文:" << endl;
	cout << message << endl;
	cout << "密文:" << endl;
	cout << ciphertext << endl;
	cout << "解密:" << endl;
	cout << cleartext << endl;
	system("pause");
}

测试:
在这里插入图片描述

今天的文章数据结构 循环队列及应用(泛型编程)分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/61860.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注