文章目录
实验1:线性表
基本就是按照思路直接写
代码:
#include<iostream>
#include<fstream>
#include<cstring>
#include<iomanip>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; //Status 是函数返回值类型,其值是函数结果状态代码。
//typedef int ElemType; //ElemType 为可定义的数据类型,此设为int类型
#define MAXSIZE 100 //表可能达到的最大长度
typedef struct
{
char no[8]; //8位学号
char name[80]; //姓名
int grade; //成绩
}Student;
//顺序表的定义(第一个程序用)
typedef struct
{
Student* elem; //指向数据元素的基地址
int length; //线性表的当前长度
}SqList;
//主函数,因为函数声明,故可放其他函数之前
int main()
{
SqList L;
int i, choose;
char name[80];
//功能定义,声明函数
Status InitList(SqList & L); //初使化顺序表
Status CreatList(SqList & L); //构建顺序表
Status TraverseList(SqList L); //显示
Status LocateElem(SqList L, char* name); //查找
Status GetElem(SqList L, int i); //获取
Status ListInsert(SqList & L, int i); //插入
Status ListDelete(SqList & L, int i); //删除
int ListLength(SqList L); //顺序表长度
Status DestroyList(SqList & L); //销毁顺序表
//屏幕提示操作!
cout << "---------------------\n";
cout << "1. 初使化顺序表\n";
cout << "2. 构建顺序表\n";
cout << "3. 显示顺序表长度\n";
cout << "4. 显示顺序表内容\n";
cout << "5. 查找学生信息\n";
cout << "6. 获取学生信息\n";
cout << "7. 插入学生信息\n";
cout << "8. 删除学生信息\n";
cout << "9. 销毁顺序表\n";
cout << "0. 退出\n\n";
cout << "---------------------\n";
choose = -1;
while (choose != 0)
{//函数调用
cout << "请选择:";
cin >> choose;
switch (choose)
{
case 1://创建顺序表
if (InitList(L))
cout << "成功建立顺序表\n\n";
else
cout << "顺序表建立失败\n\n";
break;
case 2: //构建顺序表
if (CreatList(L))
cout << "成功构建顺序表\n\n";
else
cout << "顺序表构建失败\n\n";
break;
case 3://顺序表长度
cout << ListLength(L) << "\n\n";
break;
case 4://显示顺序表内容
TraverseList(L);
break;
case 5://查找学生信息
printf("请输入需要查找信息的学生姓名:\n");
cin >> name;
if (!LocateElem(L, name))
cout << "查无此人\n\n";
break;
case 6: //获取学生信息
printf("请输入需要获取信息的学生编号:\n");
cin >> i;
if (!GetElem(L, i))
cout << "序号过大\n\n";
break;
case 7: //插入学生信息
printf("请输入要插入学生的编号:\n");
cin >> i;
if (!ListInsert(L, i))
cout << "序号太大插入失败\n\n";
else
cout << "插入成功\n\n";
break;
case 8://删除学生信息
printf("请输入要删除学生的编号:\n");
cin >> i;
if (ListDelete(L, i))
cout << "删除成功\n";
else
cout << "删除失败\n";
break;
case 9: //销毁顺序表
if (DestroyList(L)) cout << "成功删除顺序表\n\n";
else cout << "顺序表删除失败\n\n";
break;
}
getchar();
}
}
//1.初始化顺序表
Status InitList(SqList& L)
{
L.elem = new Student[MAXSIZE];
if (!L.elem) exit(OVERFLOW);
L.length = 0;
return OK;
}
//2.创建顺序表
Status CreatList(SqList& L)
{
if (!L.elem)
exit(OVERFLOW); //顺序表不存在退出
do {
printf("输入学号,姓名,成绩:\n");
cin >> L.elem[L.length].no >> L.elem[L.length].name >> L.elem[L.length].grade;
L.length++;
} while (strcmp(L.elem[L.length - 1].name, "0") != 0); //输入0 0 0时结束
L.length--;
if (L.length == 0) //长度为0 初始时输入的no就是0 顺序表内无元素 创建失败
return ERROR;
return OK;
}
//3.遍历顺序表,显示顺序表内容
Status TraverseList(SqList L)
{
for (int i = 0;i < L.length;i++)
cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl;
cout << endl;
}
//4.查找(通过姓名)
Status LocateElem(SqList L, char* name)
{
for (int i = 0;i < L.length;i++)
if (!strcmp(name, L.elem[i].name))
{
cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl << endl;
return OK;
}
return ERROR;
}
//5.获取(通过序号)
Status GetElem(SqList L, int i)
{
if (i < L.length)
{
cout << L.elem[i].no << ' ' << L.elem[i].name << ' ' << L.elem[i].grade << endl << endl;
return OK;
}
else
return ERROR;
}
//6.插入(在指定位置i插入学生信息)
Status ListInsert(SqList& L, int i)
{
char no[8];
char name[80];
int grade;
cin >> no >> name >> grade;
if (0 <= i && i <= L.length)
{
for (int j = i + 1;j <= L.length;j++)
{
L.elem[j].grade = L.elem[j - 1].grade;
strcpy(L.elem[j].name, L.elem[j - 1].name);
strcpy(L.elem[j].no, L.elem[j - 1].no);
}
L.elem[i].grade = grade;
strcpy(L.elem[i].name, name);
strcpy(L.elem[i].no, no);
L.length++;
return OK;
}
else
return false;
}
//7.删除(删除指定位置i的学生信息)
Status ListDelete(SqList& L, int i)
{
if (i >= 0 && i < L.length)
{
while (i < L.length - 1)
{
L.elem[i].grade = L.elem[i + 1].grade;
strcpy(L.elem[i].name, L.elem[i + 1].name);
strcpy(L.elem[i].no, L.elem[i + 1].no);
i++;
}
L.length--;
return OK;
}
else
return ERROR;
}
//8.返回顺序表长度
int ListLength(SqList L)
{
return L.length;
}
//9. 销毁顺序表
Status DestroyList(SqList& L)
{
if (L.elem) delete[]L.elem; //释放存储空间
L.length = 0;
return OK;
}
实验2 : 链表实现实验1
思路:
基本和实验1一样,只是加了文件读入。但是文件读入会莫名其妙读入错误数据,所以加了一个flag用来判断和使正常
代码:
#include<iostream>
#include<cstring>
#include<iomanip>
#include<fstream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; //Status 是函数返回值类型,其值是函数结果状态代码。
typedef struct
{
char no[80]; //学号
char name[80]; //姓名
int price; //成绩
}Student;
typedef struct LNode
{
Student data; //结点的数据域
struct LNode* next; //结点的指针域
} LNode, * LinkList; //LinkList为指向结构体LNode的指针类型
typedef Student ElemType; //ElemType 为可定义的数据类型,此设为Student类型
string head_1, head_2, head_3;//文件中的标题(第一行)
int length;
bool flag = 0;
int main() {
int a = 20;
int i, choose, len;
Student e;
char name[80];
LinkList L1 = NULL;
//功能定义,声明函数
Status InitList_L(LinkList & L); //初使化链表
void CreateList_H(LinkList & L, int n); //前插法构建链表
void CreateList_R(LinkList & L, int n); //后插法构建链表
int ListLength_L(LinkList L); //链表长度
Status ListDisplay1(LinkList L); //显示
Status ListDisplay2(LinkList L); //显示
LNode* LocateElem_L(LinkList L, char* e); //查找
Status GetElem_L(LinkList L, int i, Student & e); //获取元素
Status ListInsert_L(LinkList & L, int i, Student & e); //插入元素
Status ListDelete_L(LinkList & L, int i); //删除
Status DestroyList_L(LinkList & L); //销毁链表
cout << "---------------------\n";
cout << "1.初使化链表\n";
cout << "2.前插法构建链表\n";
cout << "3.后插法构建链表\n";
cout << "4.求链表长度\n";
cout << "5.显示链表内容\n";
cout << "6.查找学生信息\n";
cout << "7.获取学生信息\n";
cout << "8.插入学生信息\n";
cout << "9.删除学生信息\n";
cout << "10.销毁链表\n";
cout << "0.退出\n";
cout << "---------------------\n";
choose = -1;
while (choose != 0)
{
cout << "\n\n请选择:";
cin >> choose;
switch (choose)
{
case 1: //初始化一个单链表
if (InitList_L(L1))
cout << "成功建立链表!\n";
else
cout << "建立链表失败!\n";
break;
case 2: //使用前插法创建单链表
CreateList_H(L1, a);
cout << "输入 students.txt 信息完毕(前插法)\n";
break;
case 3: //使用后插法创建单链表
CreateList_R(L1, a);
cout << "输入 students.txt 信息完毕(后插法)\n";
break;
case 4: //求单链表长度
len = ListLength_L(L1);
cout << "当前链表长度为:" << (flag ? len-2 : len-1) << "\n";
break;
case 5: //显示链表内容
cout << "当前链表内容为:\n";
if(flag){
ListDisplay1(L1);
}else{
ListDisplay2(L1);
}
break;
case 6: //单链表的按序号取值
cout << "请输入一个位置用来取值:";
cin >> i;
if (GetElem_L(L1, i, e))
{
cout << "查找成功\n";
cout << "第" << i << "本学生证的信息是:\n";
cout << e.no << "\t" << e.name << "\t" << e.price << endl;
cout << endl;
}
else
cout << "查找失败\n";
break;
case 7: //单链表的按值查找
cout << "请输入所要查找学生姓名:";
cin >> name;
if (LocateElem_L(L1, name) != NULL)
{
e = LocateElem_L(L1, name)->data;
cout << "查找成功\n";
cout << "对应的学生信息为:\n" << e.no << "\t" << e.name << "\t" << e.price << "\n";
cout << "补充语句" << endl;
}
else
cout << "查找失败! " << name << " 没有找到\n";
break;
case 8: //单链表的插入
cout << "请输入插入的位置和学生的信息(用空格隔开):";
cin >> i;
cin >> e.no >> e.name >> e.price;
if (ListInsert_L(L1, i, e)) cout << "插入成功.\n";
else cout << "插入失败!\n";
break;
case 9: //单链表的删除
cout << "请输入所要删除的学生的编号:";
cin >> i;
if (ListDelete_L(L1, i)) cout << "删除成功!\n";
else cout << "删除失败!\n";
break;
case 10: //销毁链表
if (DestroyList_L(L1))
cout << "成功销毁链表!\n"; break;
}
}
return 0;
}
Status InitList_L(LinkList& L) { //构建
L = new LNode; //生成新结点作为头结点,用头指针L指向头结点
L->next = NULL; //头结点的指针域置空
return OK;
}
void CreateList_H(LinkList& L, int n) {
//逆位序输入 n 个元素的值,建立到头结点的单链表 L
//补充语句
LinkList p;
L = new LNode;
L->next = NULL; //先建立一个带头结点的空链表
length = 0;
fstream file; //定义文件指针 file
file.open("date\\Student.txt"); //打开数据文件,Student.txt 必须放在与源程序同一文件夹下
if (!file) { //判断文件是否存在
cout << "未找到数据文件 Student.txt,无法打开!" << endl;
exit(ERROR);
}
file >> head_1 >> head_2 >> head_3; //文件第一行:标题字符串
char no0[80], name0[80];
int price0;
// cout << head_1 << ' ' << head_2 << ' ' << head_3 << endl;
while (file >> no0 >> name0 >> price0) { // 判断是否读完数据文件内容
p = new LNode; //生成一个新结点,p 指向此结点
//从文件中读入学生信息(学号、姓名和成绩)放入结点元素内
// cout << no0 << ' ' << name0 << ' ' << price0 << endl;
strcpy(p->data.no, no0); strcpy(p->data.name, name0);
p->data.price = price0;
p->next = L->next; //连接后结点(初始首元结点) L->next = p->next;
L->next = p; //连接头结点(变成新的首元结点)
length++; //同时对链表长度进行统计(长度加 1)}
}
file.close();
}
void CreateList_R(LinkList& L, int n) //后插法构建链表
{
//补充语句
L = new LNode;
L->next = NULL; //先建立一个带头结点的空链表
LinkList p, now = L;
length = 0;
flag = 1;
fstream file; //定义文件指针 file
file.open("date\\Student.txt"); //打开数据文件,Student.txt 必须放在与源程序同一文件夹下
if (!file) { //判断文件是否存在
cout << "未找到数据文件 Student.txt,无法打开!" << endl;
exit(ERROR);
}
file >> head_1 >> head_2 >> head_3; //文件第一行:标题字符串
while (!file.eof()) { // 判断是否读完数据文件内容
p = new LNode; //生成一个新结点,p 指向此结点
//从文件中读入学生信息(学号、姓名和成绩)放入结点元素内
file >> p->data.no >> p->data.name >> p->data.price;
p->next = NULL;
now->next = p;
now = p;
length++; //同时对链表长度进行统计(长度加 1) }
}
file.close();
}
Status ListDisplay2(LinkList L) //显示链表元素的内容
{
LinkList p = L->next;
for (int k = 1; k <= length; k++) {
cout << p->data.no << '\t' << p->data.name << '\t' << p->data.price << endl;
p = p->next;
}
return OK;
}
Status ListDisplay1(LinkList L) //显示链表元素的内容
{
LinkList p = L->next;
for(int i = 1; i <= length-1; i++){
cout << p->data.no << '\t' << p->data.name << '\t' << p->data.price << endl;
p = p->next;
}
return OK;
}
LNode* LocateElem_L(LinkList L, char* str) { //根据值(字串)查找
LinkList p = L->next;
while (p->next != NULL) {
if (strcmp(p->data.name, str) == 0)
return p;
p = p->next;
}
return NULL;
}
Status GetElem_L(LinkList L, int i, Student& e) //根据序号查找
{
LinkList p = L;
if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
for (int j = 1; j <= i; j++)
p = p->next;
e = p->data;
return OK;
}
Status ListInsert_L(LinkList& L, int i, Student& e) //插入一个结点 e 的内容
{
LinkList p = L;
if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
for (int j = 1; j <= i; j++) p = p->next;
LinkList now = new LNode; now->data = e;
now->next = p->next;
p->next = now;
length++;
return OK;
}
Status ListDelete_L(LinkList& L, int i) //删除
{
if ((flag && i > length-1) || (!flag && i > length)) return ERROR;
LinkList p = L;
for (int j = 1; j <= i - 1; j++) p = p->next;
LinkList q = p->next;
p->next = q->next;
delete q; length--;
return OK;
}
Status ListLength_L(LinkList L)//求链表长度
{
int len = 0;
while (L) {
++len;
L = L->next;
}
return len;
}
Status DestroyList_L(LinkList& L) //销毁链表
{
length = 0;
LinkList p;
while (L) {
p = L;
L = L->next;
delete p;
}
return OK;
}
实验3:表达式求值
思路:
简单栈的模拟,遇到某个符号要做什么,写出来就行了。但是要注意的是输入的数不能超过9
代码:
#include<bits/stdc++.h>
using namespace std;
char op[1000];
int op_size = 0;
double num[1000];
int num_size = 0;
void solve(string s) {
op_size = 0; num_size = 0;
int k = 0;
while (s[k] == '(') k++, op[op_size++] = '(';
num[num_size++] = s[k] - '0';
for (int i = k+1; i < s.size() - 1; i++) {
if (s[i] >= '0' && s[i] <= '9') {
double x = s[i] - '0';
if (op[op_size - 1] == '*' || op[op_size - 1] == '/') {
double y = num[num_size - 1]; num_size--;
char ch = op[op_size - 1]; op_size--;
num[num_size++] = (ch == '*' ? x * y : 1.0 * y / x);
}
else {
if(op[op_size-1] == '-'){
x = -x;
op[op_size-1] = '+';
}
num[num_size++] = x;
}
continue;
}
if (s[i] == '(') {
op[op_size++] = '(';
continue;
}
if (s[i] == ')') {
while (op_size >= 1 && op[op_size - 1] != '(') {
char ch = op[op_size - 1]; op_size--;
double num1 = num[num_size - 1]; num_size--;
double num2 = num[num_size - 1]; num_size--;
num[num_size++] = (ch == '+' ? num1 + num2 : num2 - num1);
}
op_size--;
double x = num[num_size-1]; num_size--;
while(op_size >= 1 && (op[op_size-1] == '*' || op[op_size-1] == '/')){
double y = num[num_size-1]; num_size--;
char ch = op[op_size-1]; op_size--;
x = (ch == '*' ? y * x : y/x);
}
num[num_size++] = x;
continue;
}
op[op_size++] = s[i];
}
double ans = num[num_size - 1]; num_size--;
while (op_size >= 1 && num_size >= 1) {
char ch = op[op_size - 1]; op_size--;
double num1 = num[num_size - 1]; num_size--;
ans = (ch == '+' ? num1 + ans : num1 - ans);
}
cout << "计算结果为: " << ans << endl;
}
int main() {
while (1) {
cout << "---------------------------------" << endl;
cout << "0-9 以内的多项式计算" << endl;
cout << "1.计算" << endl;
cout << "0.退出\n" << endl;
cout << "选择:";
int choose;
cin >> choose;
switch(choose) {
case 1 :
{
cout << "请输入要计算的表达式(操作数和结果都在 0-9 的范围内,以#结束):" << endl;
string s; cin >> s;
solve(s);
};
break;
case 0 :
{
cout << "退出成功\n";
return 0;
};
}
}
}
实验四:字符串匹配
思路:
暴力匹配和kmp。一个是一个一个找,一个是用前缀和后缀相等优化下一次找的过程,省去不必要找的地方。
代码:
#include<iostream>
#include<cstring>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
#define MAX_STR_LEN 255 // 用户可在 255(1 个字节)以内定义最大串长
typedef char SString[MAX_STR_LEN + 1]; // 0 号单元存放串的长度
Status StrAssign(SString T, char* chars);
int StrLength(SString T);
void StrPrint(SString T);
bool Concat(SString T, SString S1, SString S2);
int Index_BF(SString S, SString T, int pos);
void get_next(SString T, int next[]);
int Index_KMP(SString S, SString T, int pos, int next[]);
void get_nextval(SString T, int nextval[]);
int main()
{
int i, * next;
char ch1[80], ch2[80];
SString S1, S2, S, SUB; // 定义串,第一个单元存储串的长度
cout << "请输入第一个字符串:";
cin >> ch1;
StrAssign(S1, ch1);
StrPrint(S1);
cout << "请输入第二个字符串:";
cin >> ch2;
StrAssign(S2, ch2);
StrPrint(S2);
cout << "------------------------------------------------\n";
cout << "第一个字符串长度为: " << StrLength(S1) << endl;
cout << "第二个字符串长度为: " << StrLength(S2) << endl;
cout << "\n============连接两个字符串构造主串==============\n";
Concat(S, S1, S2); //用 S 返回 S1 和 S2 联接而成的新串
cout << "主串长度为: " << StrLength(S) << endl;
cout << "主串为: ";
StrPrint(S);
cout << "请输入子串:";
cin >> ch2;
StrAssign(SUB, ch2);
cout << "子串长度为: " << StrLength(SUB) << endl;
cout << "\n---------------BF 匹配算法及实现----------------\n";
i = Index_BF(S, SUB, 1); // 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置 i
if (i)
printf("主串和子串在第%d 个字符处首次匹配\n", i);
else
printf("主串和子串匹配不成功\n");
cout << "\n---------------KMP 匹配算法及实现---------------\n";
next = new int[StrLength(SUB) + 1];
get_next(SUB, next); // 利用算法 4.7,求得 next 数组,存于 next 中
printf("子串的 next 数组为: ");
for (i = 1; i <= StrLength(SUB); i++)
cout << *(next + i);
printf("\n");
i = Index_KMP(S, SUB, 1, next); // 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置
if (i)
printf("主串和子串在第%d 个字符处首次匹配\n", i);
else
printf("主串和子串匹配不成功\n");
cout << "\n--------------KMP改进匹配算法及实现-------------\n";
get_nextval(SUB, next); // 利用算法 4.8,求得 next 数组,存于 next 中
printf("子串的 nextval 数组为: ");
for (i = 1; i <= StrLength(SUB); i++)
cout << *(next + i);
printf("\n");
i = Index_KMP(S, SUB, 1, next); // 利用算法 4.6 求得串 s2 在 s1 中首次匹配的位置 i
if (i)
printf("主串和子串在第%d 个字符处首次匹配\n", i);
else
printf("主串和子串匹配不成功\n");
getchar();
return 0;
}
Status StrAssign(SString T, char* chars) { //生成一个其值等于chars的串T
int i;
if (strlen(chars) > MAX_STR_LEN)
return ERROR;
else {
T[0] = strlen(chars); //第1个单元存放串的长度
for (i = 1; i <= T[0]; i++)
T[i] = chars[i - 1];
return OK;
}
}
void StrPrint(SString T)
{
int i;
for (i = 1; i <= T[0]; i++)
cout << T[i];
printf("\n");
}
int StrLength(SString T)
{
return T[0];
}
//用T返回S1和S2联接而成的新串,若未截断,则返回TRUE,否则返回FALSE
bool Concat(SString T, SString S1, SString S2)
{
int t = 0;
if (S1[0] + S2[0] <= MAX_STR_LEN)
{ // 未截断
for (int i = 1; i <= S1[0]; i++)
T[++t] = S1[i];
for (int i = 1; i <= S2[0]; i++)
T[++t] = S2[i];
T[0] = S1[0] + S2[0];
return true;
}
else
{ // 截断 S2
for (int i = 1; i <= S1[0]; i++)
T[t++] = S1[i];
for (int i = 1; i <= MAX_STR_LEN - S1[0]; i++)
T[t++] = S2[i];
T[0] = MAX_STR_LEN;
return false;
}
}
//算法4.1 BF算法
int Index_BF(SString S, SString T, int pos)
{
//返回模式T在主串S中第pos个字符之后第s一次出现的位置。若不存在,则返回值为0
//其中,T非空,1≤pos≤StrLength(S)
int i = pos;
int j = 1;
while (i <= S[0] && j <= T[0])
{
if (S[i] == T[j])
{
i++;
j++;
} //继续比较后继字符
else
{
i = i - j + 2;
j = 1;
} //指针后退重新开始匹配
if (j > T[0])
return i - j + 1;
}
return 0;
}//Index
//算法4.3 计算next函数值
void get_next(SString T, int next[])
{ //求模式串T的next函数值并存入数组next
int i = 1, j = 0;
next[1] = 0;
while (i < T[0])
if (j == 0 || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}//get_next
//算法4.2 KMP算法
int Index_KMP(SString S, SString T, int pos, int next[])
{ // 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法
//其中,T非空,1≤pos≤StrLength(S)
int i = pos, j = 1;
while (i <= S[0] && j <= T[0])
{
if (S[i] == T[j] || j == 0) // 继续比较后继字
{
i++;
j++;
}
else
j = next[j]; // 模式串向右移动
}
if (j > T[0]) // 匹配成功
return i - j + 1;
else
return 0;
}//Index_KMP
//算法4.4 计算next函数修正值
void get_nextval(SString T, int nextval[])
{ // 求模式串T的next函数修正值并存入数组nextval
int i = 1, j = 0;
nextval[1] = 0;
while (i < T[0])
if (j == 0 || T[i] == T[j])
{
i++;
j++;
if (T[i] != T[j])
nextval[i] = j;
else
nextval[i] = nextval[j];
}
else
j = nextval[j];
}//get_nextval
实验5.二叉树
思路:
简单找就好
代码:
// 5.BiTree.cpp : 定义控制台应用程序的入口点。
//
/***********************二叉树综合运算******************************/
#include<iostream>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; // Status是函数的类型
typedef char TElemType;
//二叉链表定义
typedef struct BiNode {
char data;
struct BiNode* lchild, * rchild;
} BiTNode, * BiTree;
typedef BiTree QElemType;
//链队列的定义
typedef struct QNode {
QElemType data;
QNode* next;
}*QueuePtr;
typedef struct {
QueuePtr front, rear; // 队头、队尾指针
} LinkQueue;
/***************以下为队列常用运算函数***************/
//初始化队列
Status InitQueue(LinkQueue& Q) {
// 构造一个空队列Q
Q.front = Q.rear = new QNode;
Q.front->next = NULL;
return OK;
}
//入队 算法3.17
Status EnQueue(LinkQueue& Q, QElemType e) {
// 插入元素e为Q的新的队尾元素
QNode* p = new QNode;
p->data = e;
p->next = NULL;
Q.rear->next = p; //将新结点插入队尾
Q.rear = p; //修改队尾指针
return OK;
}
//判断队空
Status QueueEmpty(LinkQueue Q) {
// 若Q为空队列,则返回TRUE,否则返回FALSE
if (Q.front->next == NULL)
return TRUE;
else
return FALSE;
}
//出队
Status DeQueue(LinkQueue& Q, QElemType& e) {
// 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR
if (Q.front == Q.rear)
return ERROR;
QNode* p = Q.front->next; //p指向队头指针
e = p->data;
Q.front->next = p->next; //修改头指针
if (Q.rear == p)
Q.rear = Q.front; //最后一个元素被删,队尾指针指向头结点
delete p;
return OK;
}
/***************以下为二叉树综合运算函数***************/
void InitBiTree(BiTree& T) {
// 操作结果:构造空二叉树T
T = NULL;
}
Status BiTreeEmpty(BiTree T) {
// 初始条件:二叉树T存在。操作结果:若T为空二叉树,则返回TRUE,否则FALSE
if (T)
return FALSE;
else
return TRUE;
}
//销毁二叉树
void DestroyBiTree(BiTree T) {
// 初始条件:二叉树T存在。操作结果:销毁二叉树T
if (T) { // 非空树
if (T->lchild) // 有左孩子
DestroyBiTree(T->lchild); // 销毁左孩子子树
if (T->rchild) // 有右孩子
DestroyBiTree(T->rchild); // 销毁右孩子子树
free(T); // 释放根结点
T = NULL; // 空指针赋0
}
}
//把指针指向给定元素
BiTree Point(BiTree T, TElemType s) { //BFS
// 返回二叉树T中指向元素值为s的结点的指针。另加
LinkQueue q;
BiTree a;
if (T) { // 非空树
InitQueue(q); // 初始化队列
EnQueue(q, T); // 根指针入队
while (!QueueEmpty(q)) { // 队不空
DeQueue(q, a); // 出队,队列元素赋给a
if (a->data == s)
return a;
if (a->lchild) // 有左孩子
EnQueue(q, a->lchild); // 入队左孩子
if (a->rchild) // 有右孩子
EnQueue(q, a->rchild); // 入队右孩子
}
}
// cout<<a->data<<endl;
return NULL;
}
//给指定结点赋值
void Assign(BiTree p, TElemType value) {
// 给p所指结点赋值为value
p->data = value;
}
求某结果左孩子的值,如无则返回空
TElemType LeftChild(BiTree T, TElemType e) {
// 初始条件:二叉树T存在,e是T中某个结点。操作结果:返回e的左孩子。若e无左孩子,则返回"空"
BiTree a;
if (T) { // 非空树
a = Point(T, e); // a是结点e的指针
if (a && a->lchild) // T中存在结点e且e存在左孩子
return a->lchild->data; // 返回e的左孩子的值
}
return ' '; // 其余情况返回空
}
求某结果右孩子的值,如无则返回空
TElemType RightChild(BiTree T, TElemType e) {
// 初始条件:二叉树T存在,e是T中某个结点。操作结果:返回e的右孩子。若e无右孩子,则返回"空"
BiTree a;
if (T) { // 非空树
a = Point(T, e); // a是结点e的指针
if (a && a->rchild) // T中存在结点e且e存在右孩子
return a->rchild->data; // 返回e的右孩子的值
}
return ' '; // 其余情况返回空
}
利用队列求取某结点双亲的值,如找不能,则返回空
TElemType Parent(BiTree T, TElemType e) { //BFS
// 初始条件:二叉树T存在,e是T中某个结点
// 操作结果:若e是T的非根结点,则返回它的双亲,否则返回"空"
LinkQueue q;
QElemType a; //BiTree a;
if (T) { // 非空树
InitQueue(q); // 初始化队列
EnQueue(q, T); // 树根指针入队
while (!QueueEmpty(q)) { // 队不空
DeQueue(q, a); // 出队,队列元素赋给a
if (a->lchild && a->lchild->data == e || a->rchild && a->rchild->data == e) // 找到e(是其左或右孩子)
return a->data; //返回e的双亲的值
else { // 没找到e,则入队其左右孩子指针(如果非空)
if (a->lchild)
EnQueue(q, a->lchild);
if (a->rchild)
EnQueue(q, a->rchild);
}
}
}
return ' '; // 树空或没找到e
}
用算法5.3 先序遍历的顺序建立二叉链表
void CreateBiTree(BiTree& T) {
//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
char ch;
cin >> ch;
if (ch == '#') T = NULL; //递归结束,建空树
else {
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
用算法5.1 中序遍历
void InOrderTraverse(BiTree T) {
//中序遍历二叉树T的递归算法
if (T) {
InOrderTraverse(T->lchild);
cout << T->data << ' ';
InOrderTraverse(T->rchild);
}
}
先序遍历
void PreOrderTraverse(BiTree T) {
//先序遍历二叉树T的递归算法
if (T) {
cout << T->data << ' ';
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
后序遍历
void PostOrderTraverse(BiTree T) {
//后序遍历二叉树T的递归算法
if (T) {
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << T->data << ' ';
}
}
//求树深度
int BiTreeDepth(BiTree T) {
int m, n, depth;
if (T == NULL) return 0; //如果是空树,深度为0,递归结束
else {
m = BiTreeDepth(T->lchild);
n = BiTreeDepth(T->rchild);
depth = max(m, n) + 1;
}
return depth;
}
//求叶子数 /
int LeafCount(BiTree T) {
if (T == NULL)
return 0; //如果是空树,返回0
if (T->lchild == NULL && T->rchild == NULL)
return 1; //如果是叶子结点,返回1
else
return LeafCount(T->lchild) + LeafCount(T->rchild);
}
求结点数/
int NodeCount(BiTree T) {
if (T == NULL)
return 0;
else
return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}
求根结点值//
TElemType Root(BiTree T) {
if (T)
return T->data;
else return ' ';
}
int main() {
BiTree T, p;
TElemType e1, e2;
int islelect;
InitBiTree(T);
cout << "------------------------------------------------------\n";
printf("构造空二叉树后,树空否?%d(1:是 0:否)树的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));
e1 = Root(T);
if (e1 != ' ')
printf("二叉树的根为: %c\n", e1);
else
printf("树空,无根\n");
cout << "------------------------------------------------------\n";
printf("请先序输入二叉树(P121图5.10(b): ABC##DE#G##F###)\n");
CreateBiTree(T);
printf("建立二叉树后,树空否?%d(1:是 0:否)", BiTreeEmpty(T));
e1 = Root(T);
if (e1 != ' ')
printf("二叉树的根为: %c\n", e1);
else
printf("树空,无根\n");
cout << "------------------------------------------------------\n";
cout << " 树的叶子数=" << LeafCount(T) << endl;
cout << " 树的结点数=" << NodeCount(T) << endl;
cout << " 树的叶深度=" << BiTreeDepth(T) << endl;
printf("\n先序递归遍历二叉树:\n");
PreOrderTraverse(T);
printf("\n中序递归遍历二叉树:\n");
InOrderTraverse(T);
printf("\n后序递归遍历二叉树:\n");
PostOrderTraverse(T);
cout << "\n------------------------------------------------------\n";
printf("\n请输入一个结点的值: ");
cin >> e1;
// cout<<e1;
p = Point(T, e1); // p为e1的指针
if (p)
printf("结点的值为%c\n", p->data);
else {
cout << "输入结点值错误!请重新输入\n";
cin >> e1;
p = Point(T, e1);
while(!p) {
cout << "输入结点值错误!请重新输入\n";
cin >> e1;
p = Point(T, e1);
}
}
cout << "\n------------------------------------------------------\n";
printf("欲改变此结点的值,请输入新值: ");
cin >> e2;
Assign(p, e2);
printf("\n先序递归遍历二叉树:");
PreOrderTraverse(T);
e1 = Parent(T, e2);
if (e1 != ' ')
printf("\n%c的双亲是%c", e2, e1);
else
printf("\n%c没有双亲\n", e2);
e1 = LeftChild(T, e2);
if (e1 != ' ')
printf("\n%c的左孩子是%c\n", e2, e1);
else
printf("\n%c没有左孩子\n", e2);
e1 = RightChild(T, e2);
if (e1 != ' ')
printf("\n%c的右孩子是%c\n", e2, e1);
else
printf("\n%c没有右孩子\n", e2);
DestroyBiTree(T);
return 0;
}
实验6:赫夫曼树
思路:
简单来说就是我们每次找两个最小的,然后一直维护就好
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int b[N];
map<int, string> mp;
struct vv {
int w, id = 0;
vv *date;
vv* pa, * l, * r;
bool operator<(const vv f)const { return f.w < w; }
vv() {
date = nullptr;
pa = nullptr;
l = nullptr;
r = nullptr;
}
};
int n;
vv* root;
void build() {
vv* node;
priority_queue<vv> q;
for (int i = 1; i <= n; i++) {
node = new vv;
cin >> node->w;
b[i] = node->w;
node->date = node;
node->id = i;
q.push(*node);
}
while (q.size() != 1) {
node = new vv;
auto x1 = q.top(); q.pop();
auto x2 = q.top(); q.pop();
node->w = x1.w + x2.w;
node->l = x1.date, node->r = x2.date;
(x1.date)->pa = node;
(x2.date)->pa = node;
node->date = node;
q.push(*node);
}
auto now = q.top(); q.pop();
root = now.date;
}
void dfs(vv* to, string s) {
if (to->l) dfs(to->l, s+'0');
if (to->r) dfs(to->r, s+'1');
if (!(to->l) && !(to->r)){
mp[to->id] = s;
}
}
int main() {
cout << "输入叶子数" << endl;
cin >> n;
cout << "输入叶子内容" << endl;
build();
dfs(root, "");
for(int i = 1; i <= n; i++){
cout << b[i] << ": " << mp[i] << endl;
}
}
实验7.1邻接矩阵
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int G[N][N];
bool vis[N];
int n, m;
//队列
struct que{
int quee[1000];
int pre = 0, end = 0;
};
void push(que &x, int y){
if(x.pre == 0){
x.quee[++(x.pre)] = y;
}
x.quee[++(x.end)] = y;
}
void pop(que &x){
x.pre++;
}
bool empty(que &x){
if(x.pre > x.end) return 1;
return 0;
}
int top(que &x){
return x.quee[x.pre];
}
void add(int u, int v, int w) {
G[u][v] = G[v][u] = min(G[v][u], w);
}
void init(){
for(int i = 1; i <= 100; i++){
for(int j = 1; j <= 100; j++){
G[i][j] = 10000;
}
}
}
//深度优先搜索
void dfs(int F[][110], int x) {
// if(x > n) return;
cout << x << ' ';
vis[x] = 1;
for (int i = 1; i <= n; i++) {
if (F[x][i] != 10000 && !vis[i]) {
vis[i] = 1;
dfs(F, i);
}
}
}
//广度优先搜索
void bfs(int F[][110], int x){
que q;
push(q, x);
cout << x << ' ';
vis[x] = 1;
while(!empty(q)){
int now = top(q); pop(q);
for(int i = 1; i <= n; i++){
if(F[now][i] != 10000 && !vis[i]){
cout << i << ' ';
vis[i] = 1;
push(q, i);
}
}
}
}
int main() {
init();
freopen("C:\\freopen\\input.txt", "r", stdin);
cout << "输入点的个数,边的个数" << endl;
cin >> n >> m;
cout << n << ' ' << m << endl;
for (int i = 1, u, v, w; i <= m; i++) {
cout << "输入边的连接关系 u-(w)->v(表示u到v有一条为w的路径)\n";
cin >> u >> v >> w;
cout << u << ' ' << v << ' ' << w << endl;
add(u, v, w);
}
int pos = 1;
cout << "请输入起点 : ";
cin >> pos;
cout << pos << endl;
cout << "\n深度优先搜索的结果是 " << endl;
dfs(G, pos);
memset(vis, 0, sizeof(vis));
cout << "\n广度优先搜索的结果是 " << endl;
bfs(G, pos);
}
实验7.2 邻接表
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
bool vis[N];
//存图----------------------
struct node{
int to, w;
node *next = nullptr;
node(){
next = NULL;
}
};
node head[N], *t;
void add(int from, int to, int w){
t = new node();
t->to = to;
t->w = w;
t->next = head[from].next;
head[from].next = t;
}
//----------------------------
//队列---------------------
struct que{
node quee[1010];
int pre = 0, end = 0;
};
void push(que &x, node y){
if(x.pre == 0){
x.quee[++(x.pre)] = y;
}
x.quee[++(x.end)] = y;
}
void pop(que &x){
x.pre++;
}
bool empty(que &x){
if(x.pre > x.end) return 1;
return 0;
}
node top(que &x){
return x.quee[x.pre];
}
//--------------
int n, m;
void dfs(int pos){
cout << pos << ' ';
vis[pos] = 1;
for(node *now = head[pos].next; now != NULL; now = now->next){
if(!vis[now->to]){
vis[now->to] = 1;
dfs(now->to);
}
}
}
void bfs(int pos){
cout << pos << ' ';
node tm = head[pos];
que q;
push(q, tm);
vis[pos] = 1;
while(!empty(q)){
node now = top(q); pop(q);
int to = now.to;
node e = *(now.next);
for(; e.next != NULL; e = *(e.next)){
if(!vis[e.to]){
vis[e.to] = 1;
cout << e.to << ' ';
push(q, head[e.to]);
}
}
if(!vis[e.to]){
if(!vis[e.to]){
vis[e.to] = 1;
cout << e.to << ' ';
push(q, head[e.to]);
}
}
}
}
int main(){
// init();
cout << "202013160226 李发展" << endl;
cout << "请输入点的个数,边的个数" << endl;
cin >> n >> m;
cout << n << ' ' << m << endl;
for(int i = 1, u,v,w; i <= m; i++){
cout << "输入边的连接关系 u-(w)->v(表示u到v有一条为w的路径)\n";
cin >> u >> v >> w;
cout << u << ' ' << v << ' ' << w << endl;
add(u,v,w);
add(v,u,w);
}
int pos;
cout << "请输入起点 : ";
cin >> pos;
cout<< "\n深度优先搜索的结果是 : " << endl;
dfs(pos);
memset(vis, 0, sizeof(vis));
cout << "\n广度优先搜索的结果是 : " << endl;
bfs(pos);
}