数据结构上机实验报告 - 线性表和栈的应用
一.集合的交、并运算
- 问题描述
设计一个能够实现求两个集合的交集和并集运算的程序- 设计要求
集合的元素限定为小写字母字符’a’’z’或数字字符’0’’9’,集合中不允许出现重复元素。集合输入的形式以’$’为结束标志,输出的结果不含重复字符或非法字符。程序以人机交互方式执行。- 数据结构
本课程设计使用单链表作为实现该问题的数据结构。
#include<iostream>
using namespace std;
typedef struct LNode {
char data;
struct LNode* next;
}LNode,*LinkList;
LinkList listA, listB;
LinkList List_TailInsert(LinkList& L) {
char x;
L = (LinkList)malloc(sizeof(LNode));
LNode* s, * r = L;
cin >> x;
while (x != '$' ) {
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
cin >> x;
}
r->next = NULL;
return L;
}
LNode* GetElem(LinkList L, int i) {
//按位置查找节点
int j = 1;
LNode* p = L->next;
if (i == 0) {
return L;
}
if (i < 1) {
return NULL;
}
while (p && j < i) {
p = p->next;
j++;
}
return p;
}
LNode* LocateElem(LinkList L, char e) {
//按值查找节点
LNode* p = L->next;
while (p != NULL && p->data != e){
p = p->next;
}
return p;
}
void DelElem(LinkList L, int i) {
LNode* p,*q;
p = GetElem(L, i - 1);
q = p->next;
p->next = q->next;
free(q);
}
void PrintList(LinkList L) {
LNode* p = L->next;
while (p->next != NULL) {
printf("%c", *p);
p = p->next;
}
printf("%c", *p);
}
int GetListLength(LinkList L) {
int len = 0;
LNode* p = L->next;
while (p->next != NULL) {
len++;
p = p->next;
}
len += 1;
return len;
}
void cross(LinkList A, LinkList B) {
LNode* NodeA = NULL;
LNode* NodeB = NULL;
NodeA = A->next;
NodeB = B->next;
while (NodeA != NULL) {
if (NodeA->data != NodeB->data) {
if (NodeB->next != NULL) {
NodeB = NodeB->next;
}
else {
NodeA = NodeA->next;
}
}
else {
printf("%c", NodeA->data);
NodeA = NodeA->next;
NodeB = B->next;
}
}
}
void connect(LinkList A, LinkList B) {
//删掉B中重复节点
//将A和B连接
int lenA = GetListLength(A);
int lenB = GetListLength(B);
for (int i = 1; i < lenA; i++) {
for (int j = 0; j < lenB; j++) {
if (GetElem(A, i)->data == GetElem(B, j)->data) {
DelElem(B, j);
lenB--;
j = 0;
}
}
}
PrintList(A);
PrintList(B);
}
int main() {
cout << "输入数组 A 以‘$’结束:" << endl;
List_TailInsert(listA);
cout << "输入数组 B 以‘$’结束:" << endl;
List_TailInsert(listB);
cout << "交集为:" << endl;
cross(listA, listB);
cout << endl << "并集为:" << endl;
connect(listA, listB);
return 0;
}
二.学生成绩管理
1.问题描述
要求以学生成绩管理业务为背景,设计一个“学生成绩管理系统”程序。对于学校来讲,学生成绩管理系统是不可缺少的组成部分,主要是对学生资料的录入、浏览、插入和删除等基本功能的实现。
2.设计要求
编制一个学生成绩管理程序。设学生成绩以一个学生一条记录的形式存储,每个学生记录包含的信息有学号和各门功课的成绩。设每位学生学习数学、英语、语文、物理和化学5门课程。
3.数据结构
本课程设计使用单链表作为实现该问题的数据结构。
#include<iostream>
#include<String>
using namespace std;
typedef struct Student{
//学生结构体
char name[10];
int id;
double mathScore;
double englishScore = 0;
double chineseScore = 0;
double physicalScore = 0;
double chemistryScore = 0;
}Student;
typedef struct LNode {
//链表
Student data;
struct LNode* next;
}LNode;
LNode* head;
void CreatListOfHead(){
//创建头结点
head = (LNode*)malloc(sizeof(LNode));
}
void InsertStudent() {
//录入学生信息
int number = 0;
LNode* s, * r;//
r = head;
cout << "录入人数:" << endl;
cin >> number;
if (number > 0) {
for (int i = 0; i < number; i++) {
s = (LNode*)malloc(sizeof(LNode));//
cout << "输入姓名:";
scanf("%s", s->data.name);
cout << "输入学号:";
scanf("%d", &s->data.id);
cout << "输入数学成绩:";
scanf("%lf", &s->data.mathScore);
cout << "输入英语成绩:";
scanf("%lf", &s->data.englishScore);
cout << "输入语文成绩:";
scanf("%lf", &s->data.chineseScore);
cout << "输入物理成绩:";
scanf("%lf", &s->data.physicalScore);
cout << "输入化学成绩:";
scanf("%lf", &s->data.chemistryScore);
r->next = s;//尾插法
r = s;
}
r->next = NULL;
}
}
void PrintStudentInfo() {
//遍历输出
LNode* p;
p = head->next;
if (head == NULL) {
cout << "无学生信息" << endl;
}
else {
printf("姓名\t学号\t成绩\n");
while (p != NULL) {
printf("%s\t%d\t数学:%.2lf\t英语:%.2lf\t语文:%.2lf\t物理:%.2lf\t化学:%.2lf\n", p->data.name, p->data.id, p->data.mathScore,p->data.englishScore,p->data.englishScore,p->data.physicalScore,p->data.chemistryScore);
p = p->next;
}
}
}
void DeleteStudent() {
//删除
int delId;
cout << "输入需要删除的学生学号:";
cin >> delId;
LNode* p = head;
while (true)
{
if (p->next && p->next->data.id == delId) {
LNode* del = p->next;
p->next = p->next->next;
cout << "已删除以下学生" << endl;
printf("姓名:%s\t学号:%d\n", del->data.name, del->data.id);
free(del);
return;
}
else {
if (p->next != NULL) {
p = p->next;
}
else {
cout << "学号不存在,删除失败" << endl;
return;
}
}
}
}
void Menu() {
int x = 0;
cout << "选择功能" << endl;
cout << "1:录入学生数据" << endl;
cout << "2:插入学生数据" << endl;
cout << "3:删除学生数据" << endl;
cout << "4:浏览学生数据" << endl;
cin >> x;
switch (x)
{
case 1:
InsertStudent();
break;
case 2:
InsertStudent();
break;
case 3:
DeleteStudent();
break;
case 4:
PrintStudentInfo();
break;
default:
cout << "输入不合法" << endl;
break;
}
}
int main() {
CreatListOfHead();
while (true) {
Menu();
}
return 0;
}
三.括号匹配
1.问题描述
设某以算术表达式中包含圆括号、方括号或花括号三种类型的括号,编写一个算法判断其中的括号是否匹配。
2.设计要求
- 程序对所输入的表达式能给出适当的提示信息,表达式中包含括号,括号分为圆括号、方括号和花括号三种类型。
- 允许使用四则混合运算(+、-、*和/),以及包含变量的算术表达式。
- 只验证表达式中的括号是否匹配(圆括号、方括号和花括号三种类型),并给出验证结果。
3.数据结构
本课程设计使用的数据结构是栈,利用顺序栈来实现。
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
struct Stack
{
int size;
char* base;
char* top;
};
bool init_stack(Stack& s)//初始化栈
{
char* tmp = new char[100];
if (tmp == NULL)
{
cout << "分配内存失败" << endl;
exit(1);
}
s.base = s.top = tmp;
s.size = 100;//最大栈容量
return true;
}
bool push(Stack& s, char ch)//插入元素
{
if (s.top - s.base > s.size - 1)//检查是否溢出
{
cout << "栈溢出" << endl;
return false;
}
*s.top = ch;//插入入元素
s.top++;//栈顶指针上移
return true;
}
bool pop(Stack& s)//删除元素
{
if (s.base == s.top)
{
return false;
}
s.top--;//顶端指针下移
}
char get_top(Stack& s)//获取栈顶元素
{
if (s.base == s.top)
{
return false;
}
char* tmp = s.top;//使用tmp表示临时指针,防止栈顶指针被修改
tmp--;
return *tmp;
}
bool empty(Stack& s)//判断是否为空栈
{
if (s.base == s.top)
return true;
else
return false;
}
//遍历全栈的函数,测试时用,能正常使用时可以不用
void traversal(Stack& s)
{
if (s.base == s.top)
{
cout << "栈为空" << endl;
return;
}
char* tmp = s.top;
tmp--;
while (tmp >= s.base)
{
cout << *tmp << "";
tmp--;
}
cout << endl;
}
int main(int argc, char const* argv[])
{
Stack s;
init_stack(s);
char str[100];
cout << "输入符号开始匹配 \"() {} []\"" << endl;
cin >> str;
for (int i = 0; i < strlen(str); ++i)
{
switch (str[i])
{
//如果是左括号都将其入栈
case '(':
push(s, '(');
break;
case '[':
push(s, '[');
break;
case '{':
push(s, '{');
break;
//如果是右括号,
case ')':
if (empty(s) || get_top(s) == ')')//判断当前栈是否为空,或者栈顶已经是右括号
push(s, ')');//继续入栈
else if (get_top(s) == '(') //如果正好前后匹配,则清除栈顶元素
pop(s);
break;
case ']':
if (empty(s) || get_top(s) == ']')
push(s, ']');
else if (get_top(s) == '[')
pop(s);
break;
case '}':
if (empty(s) || get_top(s) == '}')
push(s, '}');
else if (get_top(s) == '{')
pop(s);
break;
default:
cout << "输入不合法" << endl;
return 1;
}
}
if (s.base == s.top)
cout << "所有符号匹配成功" << endl;
else
cout << "符号: \'" << *s.base << "\' 无法配对" << endl;//输出栈底没有匹配的符号
return 0;
}
四.汉诺塔问题
1.问题描述
设有三个分别命名为X、Y和Z的塔座,在塔座X上插有n个直径各不相同,从小到大依次编号1、2、…、n的圆盘,现要求将X塔座上的n个圆盘移动到塔座Z上,并插在X、Y和Z中任一塔座;任何时候都不允许将较大的圆盘放在较小的圆盘之上。
2.设计要求
- 程序要求用户输入初始圆盘数。
- 输出所有的移动过程。
3.数据结构 本课程设计使用的数据结构是栈。利用顺序栈来实现。
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define STACKINCREMENT 5
#define STACK_INIT_SIZE 10
typedef char SElemType;
typedef int Status;
typedef struct {
SElemType* base;//栈底指针
SElemType* top;//栈顶指针
int stacksize;//当前已经分配的存储空间
}SqStack;
char prior[7][7] = {
{
'>','>','<','<','<','>','>'},{
'>','>','<','<','<','>','>'},{
'>','>','>','>','<','>','>'},
{
'>','>','>','>','<','>','>'},{
'<','<','<','<','<','=','!'},{
'>','>','>','>','!','>','>'},
{
'<','<','<','<','<','!','='} };//定义算符之间优先关系的二维数组
//构造一个存放char型数据的空栈
Status InitStack(SqStack* s) {
s->base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!s->base) return ERROR;
s->top = s->base;//栈中元素个数为0
s->stacksize = STACK_INIT_SIZE;
return OK;
}
//入栈
Status Push(SqStack* s, SElemType e) {
if (s->top - s->base >= s->stacksize) {
s->base = (SElemType*)realloc(s->base, (STACKINCREMENT + s->stacksize) * sizeof(SElemType));
if (!s->base) exit(0);
s->top = s->base + s->stacksize;
s->stacksize += STACKINCREMENT;
}
*s->top++ = e;
return OK;
}
//出栈
Status Pop(SqStack* s, SElemType* e) {
if (s->base == s->top) {
printf("空栈!\n");
return ERROR;
}
*e = *--s->top;
return OK;
}
//得到栈顶元素
SElemType GetTop(SqStack* s) {
return *(s->top - 1);
}
//确定输入的字符如果是操作符的话判断在二维数组中的下标 若是数字的话就另外与操作符区分开 便于在输入表达式时是入哪个栈
int Index(char c) {
switch (c) {
case '+': return 0;
case '-': return 1;
case '*': return 2;
case '/': return 3;
case '(': return 4;
case ')': return 5;
case '#': return 6;
default: return 7;
}
}
//判断优先级,返回大小 < > = !
char Priority(char a, char b) {
int x, y;
x = Index(a); y = Index(b);
if (x != 7 && y != 7)
return prior[x][y];
else
return '!';
}
//简单表达式求值
int Reckon(int a, char theta, int b) {
switch (theta) {
case '+':return a + b;
case '-':return a - b;
case '*':return a * b;
case '/':return a / b;
}
}
//判断是字符是否是数字
Status isdigit(char ch) {
if (ch >= '0' && ch <= '9') return OK;
return ERROR;
}
//算术表达式求值
void GetExpressionValue() {
SqStack OPTR, OPND;
SElemType result;//返回最后结果
InitStack(&OPTR);
InitStack(&OPND);
Push(&OPTR, '#');//将结束符置于操作符的底端
printf("请输入算术表达式以 # 结束 :\n");
char c = getchar();
while (c != '#' || GetTop(&OPTR) != '#') {
//当*c=='#'&&栈顶字符=='#'的时候
if (isdigit(c)) {
//如果是数字的话将其转化为数字 然后入操作数栈
int data[10];
int i, num;
i = num = 0;//num是一个中间数 用于将字符串中的数字转化为整数然后入栈 i是用于将字符串中的字符存入data数组
while (isdigit(c)) {
data[i] = c - '0';
i++;
c = getchar();
}
for (int j = 0; j < i; j++) {
num = num * 10 + data[j];
}
Push(&OPND, num);
}
else {
//如果是字符的话将其入操作符栈
SElemType a, b, theta;//a b theta是用来返回操作数栈和操作符栈里的元素的
switch (Priority(GetTop(&OPTR), c)) {
//比较即将入栈的字符与栈顶 操作符的优先级关系
case '<':Push(&OPTR, c);
c = getchar();
break;
case '>':Pop(&OPND, &b);
Pop(&OPND, &a);
Pop(&OPTR, &theta);
Push(&OPND, Reckon(a, theta, b));
break;//将结果入栈
case '=':Pop(&OPTR, &theta);
c = getchar();
break;//说明括号相遇 删除栈内括号即可
default:break;
}
}
}
Pop(&OPND, &result);
printf("结果是:%d", result);
}
int main() {
GetExpressionValue();
}
五.算术表达式求值
1.问题描述
从键盘上输入中缀算术表达式,包括圆括号,计算出表达式的值。
2.设计要求
- 程序对所输入的表达式作简单的判断,如表达式有错,能给出适当的提示。
- 实现算术四则混合运算(+、-、*和/),不含变量的整数表达式。
- 能处理双目运算符:+和-。
3.数据结构 本课程设计使用的数据结构是栈。利用顺序栈来实现。
#include <iostream>
using namespace std;
int n = 0;
int main()
{
void hanoi(int n, char a, char b, char c);//声明hanoi函数
int m;
printf("请输入总数:");
cin >> m;
printf("移动步骤为:\n");
hanoi(m, 'A', 'B', 'C');
cout << "移动总次数: " << n << endl;
return 0;
}
void hanoi(int n, char a, char b, char c)
{
void move(char a, char c);
if (n == 1)
move(a, c);
else
{
hanoi(n - 1, a, c, b);
move(a, c);
hanoi(n - 1, b, a, c);
}
}
void move(char x, char y)
{
printf("%c -> %c\n", x, y); \
n++;
}