赞
踩
一、实验目的与实验环境
1.目的:熟练掌握应用两种数据结构栈和队列,完成对应的实验题目;
2. 实验环境:Window10 64位 ,Dev-C++
二、实验内容,测试数据及程序运行结果分析
问题一:
【问题描述】假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲能有一对跳舞者。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一个程序,模拟上述舞伴配对问题。(0<m,n,k<1000)
【输入形式】第一行男士人数m和女士人数n; 第二行舞曲的数目k。
【输出形式】共k行,每行两个数,表示配对舞伴的序号,男士在前,女士在后。
【样例输入】
2 4
6
【样例输出】
1 1
2 2
1 3
2 4
1 1
2 2
思路:从题目中,易提取出关键:女队和男队是各自同时循环输出,故将循环队列封装,进行运用。
//SeqQueue.h #include <iostream> #include<cstdio> using namespace std; class Node {//定义节点 public: Node *next; int data; }; class SeqQueue { private: Node* head; int length;//循环列表元素个数 public: SeqQueue () { head = new Node(); head->next = head; head->data = 0; length = 0; } ~SeqQueue () { delete(head); } void createSeqQueue (int n); //创建单向循环链表 void traverseNode(); //遍历链表 void deleteNode(int n); //删除位置为n的结点 void insertNode(int n,int data);//在制定位置插入结点 int getLength(); //得到链表长度 bool isEmpty(); //判断链表是否为空 int getNumber(int n);//得到n位置的元素 }; void SeqQueue ::createSeqQueue (int n) { //创建单向循环链表 if(n<0) { cout << "n error " << endl; } else { length = n; Node *p,*q; p = head; for(int i=1; i<=n; i++) { q = new Node(); q->data=i; p->next = q; q->next = head; //尾节点指向头节点 p = q; } } } void SeqQueue ::traverseNode() { //遍历链表 Node *p; p = head->next; while(p!=head) { printf("%d ",p->data); p=p->next; } printf("\n"); } void SeqQueue ::deleteNode(int n) { //删除n位置的结点 if(n<0||n>length) { printf("delete is illegal\n"); return; } else { Node *p,*q; p = head; for(int i=1; i<n; i++)//找到n位置 p=p->next; q = p->next; p->next = q->next; delete q; q = NULL; length--; } } void SeqQueue ::insertNode(int n,int data) { //在n位置插入一个节点 节点的值为data Node *q,*p = new Node(); p->data = data; q = head; for(int i = 1; i<n; i++)//找到n位置 q = q->next; p->next = q->next;//插入 q->next = p; } int SeqQueue ::getNumber(int n) { Node *q = new Node(); q = head; for(int i = 1; i<=n; i++) q = q->next; return q->data; } int SeqQueue ::getLength() { //返回循环链表长度 return length; } bool SeqQueue ::isEmpty() { //判断是否为空 return head==head->next; }
main
#include <iostream> #include<cstdio> #include"SeqQueue.h" using namespace std; int main() { SeqQueue que_women,que_men; int NumberOfwomen,NumberOfmen;//女队人数,男队人数 int NumberOfsong;//歌数 scanf("%d%d%d",&NumberOfmen,&NumberOfwomen,&NumberOfsong); que_women.createSeqQueue(NumberOfwomen); que_men.createSeqQueue(NumberOfmen); int i=1;//男队出列第i号 int j=1;//女队出列第j号 for(int k=0; k<NumberOfsong; k++) { if(i>NumberOfmen) i=1; if(j>NumberOfwomen) j=1; printf("%d %d\n",que_men.getNumber(i),que_women.getNumber(j)); i++; j++; } return 0; }
性能分析:
时间复杂度是O(k),k为歌曲数目。
优化方案:
对于男队和女队数量较少时,用数组直接循环输出更方便,但数据量很大时,内存连续空间就可能不够,此时就应用队列链表。
#include <iostream> #include<cstdio> using namespace std; const int MAXN=1000; int women[MAXN],men[MAXN]; int main() { int NumberOfwomen,NumberOfmen;//女队人数,男队人数 int NumberOfsong;//歌数 cin>>NumberOfmen>>NumberOfwomen>>NumberOfsong; int k; for(k=1;k<=NumberOfwomen;k++) { women[k]=k; } for(k=1;k<=NumberOfmen;k++) { men[k]=k; } int i=1;//男队出列第i号 int j=1;//女队出列第j号 for(k=0; k<NumberOfsong; k++) { if(i>NumberOfmen) i=1; if(j>NumberOfwomen) j=1; cout<<men[i]<<" "<<women[j]<<endl; i++; j++; } return 0; }
输出结果
问题二:
【问题描述】
输入一个后缀表达式,求这个表达式的值。输入的数字皆为大于或等于零的整数,涉及的运算只有加法、减法及乘法。数字之间用空格隔开。表达式以#结束
【输入形式】 以#为结束标志的后缀表达式
【输出形式】 后缀表达式的计算结果
【样例输入】
10 5 2 3 * - 2 * + #
【样例输出】
8
思路:主要解决问题,输入类型有整形和字符型,因为字符型转整型容易,且以#为输入结束标志,所以输入变量类型为字符。
//利用str输入 #include <iostream> #include<cstdio> #include<stack> #include<cstdlib> using namespace std; int main() { stack<int> sta; string str; cin>>str; while(str!="#") { if(str=="+"||str=="-"||str=="*") {//遇符号,取出栈top1,top2进行运算,运算结果存入栈中 int n1,n2,sum; n1=sta.top(); sta.pop(); n2=sta.top(); sta.pop(); switch(str[0]) { case'+': sum=n2+n1; break; case'-': sum=n2-n1; break; case'*': sum=n2*n1; break; } sta.push(sum); } else {//遇数字,存入栈中 int temp=atoi(str.c_str());//字符串转整型 sta.push(temp); } cin>>str; } cout<< sta.top()<<endl; return 0; } //10 5 2 3 * - 2 * + #
//利用char输入 #include <iostream> #include<cstdio> #include<stack> #include<cstdlib> using namespace std; int main() { stack<int> sta; char ch; char buffer[10];//缓冲区,存暂时输入的整数 int i=0,n1,n2; int sum; scanf("%c",&ch); while(ch!='#') { while(ch>='0'&&ch<='9') {//输入整数 buffer[i++]=ch; buffer[i]='\0'; scanf("%c",&ch); if(ch==' ') {//遇到空格,输入一个完整的整数 int temp=atoi(buffer); sta.push(temp); i=0; break; } } if(ch=='+'||ch=='-'||ch=='*') { n1=sta.top(); sta.pop(); n2=sta.top(); sta.pop(); switch(ch) { case'+': sum=n1+n2; break; case'-': sum=n2-n1; break; case'*': sum=n2*n1; break; } sta.push(sum); } scanf("%c",&ch); } printf("%d\n",sta.top()); return 0; }
运行结果
问题三:
【问题描述】首先建立一个单链表,通过栈实现该链表的原地逆置,注意仅使用链表中的原有的结点空间,结点的数据成员为int型。注意这个题需要单链表和栈两个类。
【输入形式】输入只有一行,依次输入若干个整数,整数之间用一个空格分开,最后以-1结束,用表尾添加结点的方法建立一个单链表。
【输出形式】输出有2行,第1行为原链表数据,第2行为逆置后的链表数据,具体格式见样例输出
【样例输入】
1 2 3 4 5 -1
【样例输出】
1–>2–>3–>4–>5
5–>4–>3–>2–>1
#include <iostream> #include"list.h" #include<cstdio> #include<stack> using namespace std; int main() { List<int>L; L.inputRear(-1);//输入单链表 L.output();//输出原单链表 stack<int> sta; int x; for(int i=0; i<L.Length(); i++) {//输入栈 L.getData(i+1,x); sta.push(x); } for(int i=0; i<L.Length(); i++) {//栈输出,利用先进后出逆置链表 x=sta.top(); L.setData(i+1,x); sta.pop(); } L.output(); return 0; }
性能分析:
时间复杂度是O(length),length为列表长度。
优化方案:
可以采取就地逆置,但对于链表来说,双指针,一个指针指向头指针,另一个指针先遍历至链表末端后,然后两个指针指向的数据互相交换,往中间靠,直至两指针指向相等。两个思路的时间复杂度差不多,但第二个思路空间复杂度低一些。
二、实验过程中出现的问题及解决方法
第二个问题中,输入卡了很久,在用char输入的时候,所有输入输出都用cin和cout,运行结果都如下所示
反复检查代码,思路是没有逻辑问题,debug了许久,发现是输入问题,于是查询相关资料,cin和scanf对于字符输入的区别 :scanf 输入字符时,会将’\n’吸收,而cin输入字符的时候,’\n’不会被吸收。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。