数据结构上机实验报告 - 线性表和栈的应用

数据结构上机实验报告 - 线性表和栈的应用

一.集合的交、并运算

  1. 问题描述
    设计一个能够实现求两个集合的交集和并集运算的程序
  2. 设计要求
    集合的元素限定为小写字母字符’a’’z’或数字字符’0’’9’,集合中不允许出现重复元素。集合输入的形式以’$’为结束标志,输出的结果不含重复字符或非法字符。程序以人机交互方式执行。
  3. 数据结构
    本课程设计使用单链表作为实现该问题的数据结构。
#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++;
}

猜你喜欢

转载自blog.csdn.net/mercury8124/article/details/129279003