目录
实验一 图书信息管理系统的设计与实现
1.1实验目的
深入理解数据结构的基本理论,掌握数据存储结构的设计方法,掌握基于数据结构的各种操作的实现方法,训练对基础知识和基本方法的综合运用能力,增强对算法的理解能力,提高软件设计能力。在实践中培养独立分析问题和解决问题的作风和能力。
1.2实验内容
设计并实现一个图书信息管理系统。根据实验要求设计该系统的菜单和交互逻辑,并编码实现增删改查的各项功能。 该系统至少包含以下功能:
- 根据指定图书个数,逐个输入图书信息;
- 逐个显示图书表中所有图书的相关信息;
- 能根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中指定的位置;
- 根据指定的待出库的旧图书的位置,将该图书从图书表中删除;
- 能统计表中图书个数;
- 实现图书信息表的图书去重;
- 实现最爱书籍查询,根据书名进行折半查找,要求使用非递归算法实现,成功返回此书籍的书号和价格;
- 图书信息表按指定条件进行批量修改;
- 利用快速排序按照图书价格降序排序;
- 实现最贵图书的查找;
1.3 实验要求
熟练运用C++语言、基本数据结构和算法的基础知识,独立编制一个解决实际应用问题的应用序。通过题意分析、选择数据结构、算法设计、编制程序、调试程序、软件测试、结果分析、撰写课程设计报告等环节完成软件设计的全过程,不断地完善程序以提高程序的性能。
1.4 实验流程图
1.5 算法的设计与分析
1.5.1菜单界面
void meau()
{
cout << " *图书管理系统* \n";
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 << " -11.输入数据- \n";
cout << " -12.输出数据- \n";
cout << " -0.退出- \n";
cout << " |请输入选择:";
}
1.5.2结构体定义
本实验选用链表
typedef struct { //定义结构体
int num; //序号
char name[maxsize]; //书名
float price; //价格
char time[11]; //出版时间
}book;
typedef struct {
book* data; //数据存储域
int length; //长度域
book* elem; //指向数据元素的基地址
}linklist;
1.5.3 各种基本操作的函数定义
查找最喜欢的书籍操作
通过书名进行对比查看列表中是否有输入的书名,有则查找成功,否则失败
//查找您最喜爱的书籍
void FavBook(linklist& L) {
int i, n = 0;
char bookname[20];
cout << "请输入需要查找图书的书名:";
cin >> bookname;
int num = L.length;
for (i = 0; i < num; i++)
{
if (strcmp(L.data[i].name, bookname) == 0)
{
n++;
cout << "查找成功! 该图书的信息为:\n" << endl;
cout << L.data[i].num << " ";
cout << " 《" << L.data[i].name << "》 " << setiosflags(ios::fixed) << setprecision(2) << L.data[i].price << " " << L.data[i].time;
}
}
if (n == 0)
cout << "没有您最喜欢的书籍,查找失败!" << endl;
}
输入操作
bool input(linklist& L)
{
cout << "输入信息";
char i;
int y=0;
int j, k;
if (L.length > maxsize)
{
cout << "库存已满"; return false;
}
else
{
for (;; y++) {
L.data[L.length].num = L.length + 1;
cout << L.data[L.length].num << "\n";
cout << "输入书籍名称:" << endl;
cin >> L.data[L.length].name;
cout << "输入价格:"<<endl;
cin >> L.data[L.length].price;
cout << "输入出版时间:"<<endl; cin >> L.data[L.length].time;
L.length++;
cout << "结束输入?\n 是(Y) 否(other)\n选择:";
cin >> i;
if (i == 'y' || i == 'Y')
{
break;
}
if (L.length > maxsize)
{
cout << "库存已达上限!";
return false;
}
}
}
return true;
}
输出操作
//输出书籍信息
void printflist(linklist& L)
{
int i;
for (i = 0; i < L.length; i++)
{
cout << L.data[i].num << " 《" << L.data[i].name << "》 ¥" << setiosflags(ios::fixed) << setprecision(2) << L.data[i].price;
cout << " 出版时间:" << L.data[i].time;
cout << "\n";
}
}
插入操作
//插入书籍
bool insert(linklist& L, int i, book& e)
{
int j;
if (i < 1 || i < L.length + 1)//位置不合法,返回失败
{
return false;
}
i--;//对应下标状态;
for (j = L.length; j > i; j--)
{
L.data[j] = L.data[j - 1];
}//i后所有元素在顺序表上向后移动一位
strcpy(L.data[i].name, e.name);
L.data[i].price = e.price;
strcpy(L.data[i].time, e.time);
L.length = L.length + 1;
printflist(L);
return true;
}
删除操作
//删除书籍
bool deletelist(linklist& L, int i)
{
int k;
if (i<1 || i>L.length + 1) //指定元素位置不符合规定
return false;
for (k = i; k <= L.length; k++)
{
L.data[k - 1] = L.data[k]; //将后面元素依次前移
}
L.length--;
return true;
}
按照价格降序排列
//价格降序排列
void LOWprice(linklist& L)
{
int i, j;
int n = L.length;
linklist t;
t.data = (book*)malloc(maxsize * sizeof(book));
t.length = 0;
for (i = 0; i < n - 1; i++)
{
for (j = i + 1; j < n; j++)
{
if (L.data[i].price < L.data[j].price)//*
{
t.data[0] = L.data[i];
L.data[i] = L.data[j];
L.data[j] = t.data[0];
}
}
}
cout << "已完成排序:";
printflist(L);
}
查找最贵书籍操作
//查找最贵的书籍
bool findmax(linklist& L)
{
if (L.length = 0)
{
return false;
}
int i = 1, index = 0;
float exp = L.data[0].price;
while (i < L.length)
{
if (L.data[i].price > exp)
{
exp = L.data[i].price;
index = i;
}
}
cout << "最贵的图书信息如下:";
cout << L.data[index].num << " 《" << L.data[index].name;
cout << "》 ¥" << L.data[index].price << " 出版时间:" << L.data[index].time;
}
修改书籍价格操作
//修改书籍价格
void money(linklist& L)
{
double sum = 0;
int i;
for (i = 0; i < L.length; i++)
{
sum += L.data[i].price;
}
sum /= L.length;
i = 0;
while (i < L.length)
{
if (L.data[i].price < sum)
{
L.data[i].price = L.data[i].price * 6 / 5;
}
else
{
L.data[i].price = L.data[i].price * 11 / 10;
}
}
cout << "已完成价格改动\n";
printflist(L);
}
主函数
int main()
{
linklist L;
book e;
init(L);
int choice;
do {
char a;
system("cls");
meau();
cin >> choice;
switch (choice) {
case 1:init(L); input(L); break;
case 2:cout << "分别输入书名、价格、出版时间:"; cin >> e.name >> e.price >> e.time;
cout << "想插入的位置:";
cin >> e.num;
insert(L, e.num, e);
break;
case 3:printflist(L);
cout << "输入需要删除数据的编号:";
int z; cin >> z;
if (deletelist(L, z) == 1)
cout << "删除成功!";
else
cout << "数据非法!!!"; cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 4:for (int i1 = 1; i1 <= L.length; i1++)
{
deletelist(L, i1);
}
cout << "已删除所有数据";
cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 5:
break;
case 6:printflist(L);
cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 7:money(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 8:chaname(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 9:FavBook(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 10: LOWprice(L); cout << "按c键退出"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 11:input(L); cout << "按c键退出"; cin >> a;
if (a == 'C' || a == 'C') {
break;
}
case 12: printflist(L); cout << "按c键退出"; cin >> a;
if (a == 'C' || a == 'C') {
break;
}
}
} while (choice != 0);
return 0;
}
1.6 完整代码
方法一
#pragma warning(disable:4996)
#include<iostream>
#include<string.h>
#include <cassert>
#include <iomanip>
#include<fstream>
#include<stdlib.h>
#include<conio.h>
#include<malloc.h>
#define maxsize 30
using namespace std;
typedef struct { //定义结构体
int num; //序号
char name[maxsize]; //书名
float price; //价格
char time[11]; //出版时间
}book;
typedef struct {
book* data; //数据存储域
int length; //长度域
book* elem; //指向数据元素的基地址
}linklist;
void init(linklist& L)
{
L.data = (book*)malloc(maxsize * sizeof(book));
L.length = 0;
}
//输入书籍
bool input(linklist& L)
{
cout << "输入信息";
char i;
int y=0;
int j, k;
if (L.length > maxsize)
{
cout << "库存已满"; return false;
}
else
{
for (;; y++) {
L.data[L.length].num = L.length + 1;
cout << L.data[L.length].num << "\n";
cout << "输入书籍名称:" << endl;
cin >> L.data[L.length].name;
cout << "输入价格:"<<endl;
cin >> L.data[L.length].price;
cout << "输入出版时间:"<<endl; cin >> L.data[L.length].time;
L.length++;
cout << "结束输入?\n 是(Y) 否(other)\n选择:";
cin >> i;
if (i == 'y' || i == 'Y')
{
break;
}
if (L.length > maxsize)
{
cout << "库存已达上限!";
return false;
}
}
}
return true;
}
//输出书籍信息
void printflist(linklist& L)
{
int i;
for (i = 0; i < L.length; i++)
{
cout << L.data[i].num << " 《" << L.data[i].name << "》 ¥" << setiosflags(ios::fixed) << setprecision(2) << L.data[i].price;
cout << " 出版时间:" << L.data[i].time;
cout << "\n";
}
}
//插入书籍
bool insert(linklist& L, int i, book& e)
{
int j;
if (i < 1 || i < L.length + 1)//位置不合法,返回失败
{
return false;
}
i--;//对应下标状态;
for (j = L.length; j > i; j--)
{
L.data[j] = L.data[j - 1];
}//i后所有元素在顺序表上向后移动一位
strcpy(L.data[i].name, e.name);
L.data[i].price = e.price;
strcpy(L.data[i].time, e.time);
L.length = L.length + 1;
printflist(L);
return true;
}
//删除书籍
bool deletelist(linklist& L, int i)
{
int k;
if (i<1 || i>L.length + 1) //指定元素位置不符合规定
return false;
for (k = i; k <= L.length; k++)
{
L.data[k - 1] = L.data[k]; //将后面元素依次前移
}
L.length--;
return true;
}
//价格降序排列
void LOWprice(linklist& L)
{
int i, j;
int n = L.length;
linklist t;
t.data = (book*)malloc(maxsize * sizeof(book));
t.length = 0;
for (i = 0; i < n - 1; i++)
{
for (j = i + 1; j < n; j++)
{
if (L.data[i].price < L.data[j].price)//*
{
t.data[0] = L.data[i];
L.data[i] = L.data[j];
L.data[j] = t.data[0];
}
}
}
cout << "已完成排序:";
printflist(L);
}
//查找最贵的书籍
bool findmax(linklist& L)
{
if (L.length = 0)
{
return false;
}
int i = 1, index = 0;
float exp = L.data[0].price;
while (i < L.length)
{
if (L.data[i].price > exp)
{
exp = L.data[i].price;
index = i;
}
}
cout << "最贵的图书信息如下:";
cout << L.data[index].num << " 《" << L.data[index].name;
cout << "》 ¥" << L.data[index].price << " 出版时间:" << L.data[index].time;
}
//查找您最喜爱的书籍
void FavBook(linklist& L) {
int i, n = 0;
char bookname[20];
cout << "请输入需要查找图书的书名:";
cin >> bookname;
int num = L.length;
for (i = 0; i < num; i++)
{
if (strcmp(L.data[i].name, bookname) == 0)
{
n++;
cout << "查找成功! 该图书的信息为:\n" << endl;
cout << L.data[i].num << " ";
cout << " 《" << L.data[i].name << "》 " << setiosflags(ios::fixed) << setprecision(2) << L.data[i].price << " " << L.data[i].time;
}
}
if (n == 0)
cout << "没有您最喜欢的书籍,查找失败!" << endl;
}
//修改书籍价格
void money(linklist& L)
{
double sum = 0;
int i;
for (i = 0; i < L.length; i++)
{
sum += L.data[i].price;
}
sum /= L.length;
i = 0;
while (i < L.length)
{
if (L.data[i].price < sum)
{
L.data[i].price = L.data[i].price * 6 / 5;
}
else
{
L.data[i].price = L.data[i].price * 11 / 10;
}
}
cout << "已完成价格改动\n";
printflist(L);
}
//根据书名查找书籍
void chaname(linklist& L) //根据书名查找信息
{
int i, n = 0;
char bookname[20];
cout << "请输入需要查找图书的书名:";
cin >> bookname;
int num = L.length;
for (i = 0; i < num; i++)
{
if (strcmp(L.data[i].name, bookname) == 0)
{
n++;
cout << "查找成功! 该图书的信息为:\n" << endl;
cout << L.data[i].num << " ";
cout << " 《" << L.data[i].name << "》 " << setiosflags(ios::fixed) << setprecision(2) << L.data[i].price << " " << L.data[i].time;
}
}
if (n == 0)
cout << "查找失败!" << endl;
}
void meau()
{
cout << " *图书管理系统* \n";
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 << " -11.输入数据- \n";
cout << " -12.输出数据- \n";
cout << " -0.退出- \n";
cout << " |请输入选择:";
}
int main()
{
linklist L;
book e;
init(L);
int choice;
do {
char a;
system("cls");
meau();
cin >> choice;
switch (choice) {
case 1:init(L); input(L); break;
case 2:cout << "分别输入书名、价格、出版时间:"; cin >> e.name >> e.price >> e.time;
cout << "想插入的位置:";
cin >> e.num;
insert(L, e.num, e);
break;
case 3:printflist(L);
cout << "输入需要删除数据的编号:";
int z; cin >> z;
if (deletelist(L, z) == 1)
cout << "删除成功!";
else
cout << "数据非法!!!"; cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 4:for (int i1 = 1; i1 <= L.length; i1++)
{
deletelist(L, i1);
}
cout << "已删除所有数据";
cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 5:
break;
case 6:printflist(L);
cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 7:money(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 8:chaname(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 9:FavBook(L); cout << "按c键退出\n"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 10: LOWprice(L); cout << "按c键退出"; cin >> a;
if (a == 'c' || a == 'C') {
break;
}
case 11:input(L); cout << "按c键退出"; cin >> a;
if (a == 'C' || a == 'C') {
break;
}
case 12: printflist(L); cout << "按c键退出"; cin >> a;
if (a == 'C' || a == 'C') {
break;
}
}
} while (choice != 0);
return 0;
}
方法二
#include <iostream>
#include <cstring>
#include <climits>
#include <algorithm>
#include <iomanip>
using namespace std;
typedef struct {
char no[8]; //8位书号
char name[20]; //书名
float price; //价格
}Book;
typedef struct {
Book *elem; //指向数据元素的基地址
int length; //线性表的当前长度
}SqList;
// global variable
SqList head;
// Declaration
void ShowBooks();
void inputBooks(){
// input books
while (1){
Book * p = new Book[head.length + 1];
Book * tmp = head.elem;
if(head.length > 0){
memcpy ( p, head.elem, sizeof(Book) * head.length);
}
head.elem = p;
if(head.length > 0) {
delete[] tmp;
}
Book * target = head.elem + head.length;
Book tmp_book;
cin >> tmp_book.no >> tmp_book.name >> tmp_book.price;
if(strcmp(tmp_book.no, "0") == 0 && strcmp(tmp_book.name, "0") == 0 && tmp_book.price == 0){
break;
}
else{
strcpy(target->no, tmp_book.no);
strcpy(target->name, tmp_book.name);
target->price = tmp_book.price;
}
head.length ++;
}
}
void AdjustPrice(){
inputBooks();
float sum = 0;
float AvgPrice = 0;
for (int i = 0; i < head.length; ++i) {
sum += (head.elem + i)->price;
}
AvgPrice = sum / head.length;
for (int i = 0; i < head.length; ++i) {
if((head.elem + i)->price >= AvgPrice)
{
(head.elem + i)->price *= 1.1;
}
else{
(head.elem + i)->price *= 1.2;
}
}
ShowBooks();
}
void ShowBooks(){
for (int i = 0; i < head.length; ++i) {
cout << (head.elem + i)->no << " " << (head.elem + i)->name << " " << setiosflags(ios::fixed) << std::setprecision(2) << (head.elem + i)->price << endl;
}
}
bool compareTwoBooks(Book a, Book b)
{
return (a.price > b.price);
}
void ShowMax(){
inputBooks();
int ShowCount;
cin >> ShowCount;
sort(head.elem, head.elem + head.length, compareTwoBooks);
for (int i = 0; i < ShowCount; ++i) {
cout << (head.elem + i)->no << " " << (head.elem + i)->name << " " << setiosflags(ios::fixed) << std::setprecision(2) << (head.elem + i)->price << endl;
}
}
void ShowFavBook(){
inputBooks();
int ShowCount = 0;
char target[100];
cin >> target;
for (int i = 0; i < head.length; ++i) {
char *output = NULL;
output = strstr ((head.elem + i)->name, target);
if(output) {
ShowCount++;
}
}
if(ShowCount > 0){
cout << ShowCount << endl;
for (int i = 0; i < head.length; ++i) {
char *output = NULL;
output = strstr ((head.elem + i)->name, target);
if(output) {
cout << (head.elem + i)->no << " " << (head.elem + i)->name << " " << setiosflags(ios::fixed) << std::setprecision(2) << (head.elem + i)->price << endl;
}
}
}
else{
cout << "抱歉,没有你的最爱!" << endl;
}
}
void insertBook(){
int pos;
inputBooks();
cin >> pos;
if(pos > head.length || pos < 0){
cout << "抱歉,入库位置非法!" << endl;
return;
}
Book * p = new Book[head.length + 1];
memcpy ( p, head.elem, sizeof(Book) * (pos - 1));
memcpy ( p + pos, head.elem + pos - 1, sizeof(Book) * (head.length - pos + 1));
cin >> (p + (pos - 1))->no >> (p + (pos - 1))->name >> (p + (pos - 1))->price;
delete[] head.elem;
head.elem = p;
head.length ++;
ShowBooks();
}
void deleteBook(){
char bookno[100];
cin >> bookno;
int pos = -1;
for (int i = 0; i < head.length; ++i) {
if(strcmp((head.elem + i)->no, bookno) == 0){
pos = i;
break;
}
}
if(pos != -1){
Book * p = new Book[head.length - 1];
memcpy ( p, head.elem, sizeof(Book) * (pos - 1));
memcpy ( p + pos + 1, head.elem + pos, sizeof(Book) * (head.length - pos));
head.length --;
ShowBooks();
}
else{
cout << "出库失败,未找到该图书!" << endl;
}
}
void deleteByIndex(int pos){
Book * p = new Book[head.length - 1];
memcpy ( p, head.elem, sizeof(Book) * pos);
memcpy ( p + pos + 1, head.elem + pos, sizeof(Book) * (head.length - pos));
head.length --;
}
void removeDuplicate(){
inputBooks();
int curIndex = 0;
while (1){
char curNo[100];
strcpy(curNo, head.elem[curIndex].no);
bool isDelete = false;
while (!isDelete){
isDelete = false ;
for(int i=curIndex; i < head.length; i++){
if(strcmp(curNo, head.elem[i].no) == 0){
deleteByIndex(i);
isDelete = true;
break;
}
}
}
if(++curIndex >= head.length) break;
}
cout << head.length << endl;
ShowBooks();
}
int main()
{
head.elem = NULL;
head.length = 0;
// inputBooks();
// AdjustPrice();
// ShowMax();
// ShowFavBook();
// insertBook();
removeDuplicate();
return 0;
}
1.7 程序运行结果截图(部分功能)
菜单
输入书籍信息
输出书籍
按价格排序
查询最喜爱的书籍
删除书籍
1.8 时间复杂度分析
采用链表的存储结构,在执行输入、插入和删除操作时,时间复杂度是O(1),
在执行查找最喜欢的书籍时,时间复杂度是O(n).
算法的空间复杂度是O(n).
1.9总结与反思
这次课设我做的图书管理系统,开始以前,我感觉特容易。但没想到实现起来还是困难重重,例如指针、文件等知识的缺失自己只能请同学帮忙,还有一些课堂上的小知识,本以为记住了但用起来不熟练,只知其一不知其二,导致耗费大量时间。总结起来,共有以下一些问题:
(1)本系统由准备不充分,功能不太完善。给系统的使用带来了不便。
(2)由于以前没有做过什么项目,所以在这次程序设计的过程中可以说道路是曲折的。有经验,很多事情考虑不周。
(3)程序界面做的不太完善。
(4)本次实验写了两次代码,方法一相较于方法二更加完善更具可观性
我在本次课程设计中体会颇多,我知道了光说不练是不行的。通过本次实践总结其中不足,积累经验。在今后的学习生活中不断的积累知识,希望在将来能够作出更好的系统来。
实验二 隐式图的搜索问题
2.1实验内容
编写九宫重排问题的启发式搜索(A*算法)求解程序。
在3х3组成的九宫棋盘上,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,编程给出一个最优的走法序列。输出每个状态的棋盘
2.2实验所运用的知识
2.2.1 A※算法
A*算法是启发式搜索,是一种尽可能基于现有信息的搜索策略,也就是说搜索过程中尽量利用目前已知的诸如迭代步数,以及从初始状态和当前状态到目标状态估计所需的费用等信息。
A*算法可以选择下一个被检查的节点时引入了已知的全局信息,对当前结点距离终点的距离作出估计,作为评价该节点处于最优路线上的可能性的量度,这样可以首先搜索可能性大的节点,从而提高了搜索过程的效率。
A*算法的基本思想如下:引入当前节点j的估计函数f*,当前节点j的估计函数定义为:
f*(j)= g(j)+h*(j)
其中g(j)是从起点到当前节点j的实际费用的量度,h*(j)是从节点j到终点的最小费用的估计,可以依据实际情况,选择h*(j)的具体形式,h*(j)要满足一个要求:不能高于节点j到终点的实际最小费用。从起始节点点向目的节点搜索时,每次都搜索f*(j)最小的节点,直到发现目的节点。
2.2.2 A※算法详解
评价函数:f(n)=g(n)+h(n)
g(n) 表示从起始节点到节点n的开销代价值,
h(n) 表示从节点n到目标节点路径中所估算的最小开销代价值,
f(n) 视为经过节点n、具有最小开销代价值的路径。
为了保证A*算法是最优(optimal),需要启发函数 h(n) 是可容的(admissible heuristic)和一致的(consistency,或者也称单调性,即 monotonicity)
算法思路
定义open 表和close 表,其中open表是用来存放待查验的节点,而close表是用来存放已查验过的节点(也就是我们不需要再关注的节点)
①把开始节点加入open 表.
②将开始节点拓展的子节点(相邻节点)加入open表,将开始节点加入到close 表.
③将open表中的节点的f值进行从小到大的排序,每次从open表中取出第一个节点(也就是f值最小的节点)进行判断,如果这个节点是目标节点,则算法结束,无需进行以下步骤;反之,如果这个节点不是目标节点,则将这个节点n进行扩展,再进行第④步。
④判断n的可扩展节点m(相邻节点),情况一:如果m在open表中,则说明从初始节点到m节点出现了两条路径,此时需要判断这两条路径的f值的大小,如果是新路径的f值大,则需要更改m节点的父节点,如果是新路径的f值小,则不需要做任何操作;情况二:如果m在close表中,则说明从初始节点到m节点有两条路径,如果是新路径的f值大,则不需要操作,如果是新路径的f值小,则需要更改m的父节点,并将m节点从close表中取出,放入到open表中;情况三:m节点既不在open表中也不在close表中,直接将m节点加入到open表中即可;
⑤重复第③步(算法结束的两种情况:其一:当前节点就是目标节点,即找到了最优解;其二:open表为空,即无法找到与目标节点相同的节点,即无解
启发式搜索策略
启发式搜索算法的描述:
(1)把初始节点S0 放入Open表中,f(S0)=g(S0)+h(S0);
(2)如果Open表为空,则问题无解,失败退出;
(3)把Open表的第一个节点取出放入Closed表,并记该节点为n;
(4)考察节点n是否为目标节点。若是,则找到了问题的解,成功退出;
(5)若节点n不可扩展,则转到第(2)步;
(6)扩展节点n,生成子节点ni(i=1,2,……),计算每一个子节点的估价值f(ni) (i=1,2,……),并为每一个子节点设置指向父节点的指针,然后将这些子节点放入Open表中;
(7)根据各节点的估价函数值,对Open表中的全部节点按从小到大的顺序重新进行排序;
(8)转到第(2)步。
启发式搜索算法的工作过程:
2.3 流程图
2.4算法设计与分析
结构体定义和三个估值函数的建立
struct ENode
{
int status[9];//存储节点的状态
int G; //存储走的是第几步
int H;//存储不在位的节点数
int F;//存储总耗散值
int Zero;//存储‘0’节点所在位置
int step;//存储该节点是上一节点通过怎样的移动得到的
ENode *Parent;
};
open表和close表的建立
open和close是表中最后一个内容的下一位序号
//定义OPEN表和CLOSE表
ENode OPEN[MAXLISTSIZE];
ENode CLOSE[MAXLISTSIZE];
int open = 0;
int close = 0;
ENode *Node;
搜索最佳路径中的变化操作
/*
计算不在位的节点H
返回 H
*/
int CountH(int *status)
{
int H = 0;
int i;
for (i = 0; i <= 8; i++)
{
if (FinalStatus[i] != status[i])
{
H++;
}
}
return H;
}
/*
判断新生成的节点是否已经存在于OPEN表或CLOSE表中
*/
int Exist(ENode *N)
{
int i, j;
int H = 0; //计算不在位的节点,如果为0,则证明给函数的节点在表中已存在
int status[9];
Node = new ENode;
Node = N;
for (i = 0; i <= 8; i++)
{
status[i] = Node->status[i];
}
for (i = 0; i <= open - 1; i++) //判断是否在OPEN表
{
for (j = 0; j <= 8; j++)
{
if (status[j] != OPEN[i].status[j])
{
H++;
}
}
if (H == 0) //H=0证明在表中找到该节点
{
return i + 1; //如果在OPEN表中,返回i(节点在OPEN的位置)+ 1(在OPEN找到该节点)
}
H = 0; //扫描完一个节点后重置H
}
for (i = 0; i <= close - 1; i++) //判断是否在CLOSE表
{
for (j = 0; j <= 8; j++)
{
if (status[j] != CLOSE[i].status[j])
{
H++;
}
}
if (H == 0) //H=0证明在表中找到该节点
{
return (-i) - 1; //如果在CLOSE表中,返回-i(i为节点在CLOSE的位置)- 1(在CLOSE找到该节点)
}
H = 0; //扫描完一个节点后重置H
}
return 0;
}
/*
初始化节点
*/
ENode *ENodeInit(int *status, int zero, int g, ENode *parent, int step)
{
int i;
Node = new ENode;
for (i = 0; i <= 8; i++)
{
Node->status[i] = status[i];
}
Node->Zero = zero;
Node->G = g;
Node->H = CountH(Node->status);
Node->F = Node->G + Node->H;
Node->Parent = parent;
Node->step = step;
return Node;
}
//左移后的变化
int *Left(int *s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z - 1];
status[z - 1] = 0;
status[z] = temp;
return status;
}
//右移后的变化
int *Right(int *s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z + 1];
status[z + 1] = 0;
status[z] = temp;
return status;
}
//上移后的变化
int *Up(int *s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z - 3];
status[z - 3] = 0;
status[z] = temp;
return status;
}
//下移后的变化
int *Down(int *s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z + 3];
status[z + 3] = 0;
status[z] = temp;
return status;
}
/*
判断子节点是否在OPEN或CLOSE中,并进行对应的操作
返回值 NULL
*/
void ExistAndOperate(ENode *N)
{
int i;
int inList; //定义表示新生成节点是否在OPEN表或CLOSE表中
Node = new ENode;
Node = N;
if (Node->G == 1) //如果是第一步的节点,直接加入OPEN中,返回
{
OPEN[open] = *Node;
open++;
return;
}
inList = Exist(Node); //判断新节点是否在OPEN或CLOSE中
if (inList == 0) //如果均不在两个表中,将节点加入OPEN表中
{
OPEN[open] = *Node; //将拓展出的新结点加入到OPEN表中
open++;
}
else if (inList > 0) //如果在OPEN中,说明从初始节点到该节点找到了两条路径,保留耗散值短的那条路径
{
if (OPEN[inList - 1].F > Node->F) //如果表内节点F值大于新节点F值,用新节点代替表内节点
{
OPEN[inList - 1] = *Node;
}
}
else if (inList < 0) //如果在CLOSE中,说明初始节点到该节点有两条路径,如果新找到的路径耗散值大,什么都不做,如果较小,将其从CLOSE中取出放入OPEN中
{
inList = -inList;
if (CLOSE[inList - 1].F > Node->F) //如果较小
{
OPEN[open] = *Node; //将其取出放入OPEN
open++;
}
for (i = inList - 1; i <= close - 1; i++) //将其在CLOSE中释放
{
CLOSE[i] = CLOSE[i + 1];
}
close--;
}
}
寻找最佳路径函数
ENode* Search()
{
int* status;
int i, j;
ENode* Temp;
while (1) //一直循环知道找到解结束
{
Temp = new ENode;
for (i = open - 1; i > 0; i--) //用冒泡排序给OPEN表里面的节点按耗散值进行排序
{
for (j = 0; j < i; j++)
{
if (OPEN[j].F > OPEN[j + 1].F)
{
*Temp = OPEN[j + 1];
OPEN[j + 1] = OPEN[j];
OPEN[j] = *Temp;
}
}
}
Node = new ENode;
*Node = OPEN[0]; //从OPEN表中取出第一个元素(F值最小)进行扩展
if (!CountH(Node->status)) //判断该节点是否是目标节点,若是,则不在位的将牌数为0,算法结束
{
break;
}
Temp = Node;
CLOSE[close] = *Node; //将扩展过的节点放入CLOSE
close++;
for (i = 0; i <= open - 1; i++) //将扩展的节点从OPEN中释放
{
OPEN[i] = OPEN[i + 1];
}
open--;
if ((Temp->Zero) % 3 >= 1) //如果能左移,则进行左移创造新结点
{
Node = new ENode; //创造新结点
status = Left(Temp->status, Temp->Zero); //得到新的状态
Node = ENodeInit(status, Temp->Zero - 1, (Temp->G) + 1, Temp, 1); //初始化新结点
ExistAndOperate(Node); //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
}
if ((Temp->Zero) % 3 <= 1) //如果能右移,则进行右移创造新结点
{
Node = new ENode;
status = Right(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero + 1, (Temp->G) + 1, Temp, 2);
ExistAndOperate(Node);
}
if (Temp->Zero >= 3) //如果能上移,则进行上移创造新结点
{
Node = new ENode;
status = Up(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero - 3, (Temp->G) + 1, Temp, 3);
ExistAndOperate(Node);
}
if (Temp->Zero <= 5) //如果能下移,则进行下移创造新结点
{
Node = new ENode;
status = Down(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero + 3, (Temp->G) + 1, Temp, 4);
ExistAndOperate(Node);
}
if (open == 0) //如果open=0, 证明算法失败, 没有解
return NULL;
}
return Node;
}
主函数
int main() { int fstatus[9]; int i; ENode *FNode; ENode *EndNode; for (i = 0; i <= 8; i++) //输入初始状态 { cin >> fstatus[i]; } for (i = 0; i <= 8; i++) //判断0节点位置 { if (fstatus[i] == 0) break; } FNode = ENodeInit(fstatus, i, 0, NULL, 0); //获得初始节点 OPEN[open] = *FNode; //将初始节点放入OPEN中 open++; EndNode = Search(); //寻找最佳路径 if (!EndNode) cout << "无解" << endl; else ShowStep(EndNode); //展示步骤 return 0; }
2.5 完整代码
#include <iostream>
using namespace std;
#define MAXLISTSIZE 10000
#define MAXSTEPSIZE 10000
struct ENode
{
int status[9];//存储节点的状态(即八数码的排列
int G;//存储走的是第几步
int H; //存储不在位的节点数
int F;//存储总耗散值
int Zero;//存储‘0’节点所在位置
int step;//存储该节点是上一节点通过怎样的移动得到的
ENode* Parent;
};
//最终状态
int FinalStatus[9] = { 1, 2, 3, 8, 0, 4, 7, 6, 5 };
//定义OPEN表和CLOSE表,open和close是表中最后一个内容的下一位序号
ENode OPEN[MAXLISTSIZE];
ENode CLOSE[MAXLISTSIZE];
int open = 0;
int close = 0;
ENode* Node;
/*
计算不在位的将牌数H
返回 H
*/
int CountH(int* status)
{
int H = 0;
int i;
for (i = 0; i <= 8; i++)
{
if (FinalStatus[i] != status[i])
{
H++;
}
}
return H;
}
/*
判断新生成的节点是否已经存在于OPEN表或CLOSE表中
返回 表征是否存在于OPEN或CLOSE的值,值为0 均不在,值>0 只在OPEN表,值<0 只在CLOSE表,|值|-1表示所在列表中的位置
*/
int Exist(ENode* N)
{
int i, j;
int H = 0; //计算不在位的节点数,如果为0,则证明给函数的节点在表中已存在
int status[9];
Node = new ENode;
Node = N;
for (i = 0; i <= 8; i++)
{
status[i] = Node->status[i];
}
for (i = 0; i <= open - 1; i++) //判断是否在OPEN表
{
for (j = 0; j <= 8; j++)
{
if (status[j] != OPEN[i].status[j])
{
H++;
}
}
if (H == 0) //H=0证明在表中找到该节点
{
return i + 1; //如果在OPEN表中,返回i(节点在OPEN的位置)+ 1(在OPEN找到该节点)
}
H = 0; //扫描完一个节点后重置H
}
for (i = 0; i <= close - 1; i++) //判断是否在CLOSE表
{
for (j = 0; j <= 8; j++)
{
if (status[j] != CLOSE[i].status[j])
{
H++;
}
}
if (H == 0) //H=0证明在表中找到该节点
{
return (-i) - 1; //如果在CLOSE表中,返回-i(i为节点在CLOSE的位置)- 1(在CLOSE找到该节点)
}
H = 0; //扫描完一个节点后重置H
}
return 0;
}
/*
初始化节点
返回 初始化后的节点Node
*/
ENode* ENodeInit(int* status, int zero, int g, ENode* parent, int step)
{
int i;
Node = new ENode;
for (i = 0; i <= 8; i++)
{
Node->status[i] = status[i];
}
Node->Zero = zero;
Node->G = g;
Node->H = CountH(Node->status);
Node->F = Node->G + Node->H;
Node->Parent = parent;
Node->step = step;
return Node;
}
/*
左移后的变化
返回 左移后的状态
*/
int* Left(int* s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z - 1];
status[z - 1] = 0;
status[z] = temp;
return status;
}
/*
右移后的变化
返回 右移后的状态
*/
int* Right(int* s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z + 1];
status[z + 1] = 0;
status[z] = temp;
return status;
}
/*
上移后的变化
返回 上移后的状态
*/
int* Up(int* s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z - 3];
status[z - 3] = 0;
status[z] = temp;
return status;
}
/*
下移后的变化
返回 下移后的状态
*/
int* Down(int* s, int z)
{
int temp, i;
static int status[9];
for (i = 0; i <= 8; i++)
{
status[i] = s[i];
}
temp = status[z + 3];
status[z + 3] = 0;
status[z] = temp;
return status;
}
/*
判断子节点是否在OPEN或CLOSE中,并进行对应的操作
返回值 NULL
*/
void ExistAndOperate(ENode* N)
{
int i;
int inList; //定义表示新生成节点是否在OPEN表或CLOSE表中, 值为0 均不在,值>0 只在OPEN表,值<0 只在CLOSE表
Node = new ENode;
Node = N;
if (Node->G == 1) //如果是第一步的节点,直接加入OPEN中,返回
{
OPEN[open] = *Node;
open++;
return;
}
inList = Exist(Node); //判断新节点是否在OPEN或CLOSE中
if (inList == 0) //如果均不在两个表中,将节点加入OPEN表中
{
OPEN[open] = *Node; //将拓展出的新结点加入到OPEN表中
open++;
}
else if (inList > 0) //如果在OPEN中,说明从初始节点到该节点找到了两条路径,保留耗散值短的那条路径
{
if (OPEN[inList - 1].F > Node->F) //如果表内节点F值大于新节点F值,用新节点代替表内节点
{
OPEN[inList - 1] = *Node;
}
}
else if (inList < 0) //如果在CLOSE中,说明初始节点到该节点有两条路径,如果新找到的路径耗散值大,什么都不做,如果较小,将其从CLOSE中取出放入OPEN中
{
inList = -inList;
if (CLOSE[inList - 1].F > Node->F) //如果较小
{
OPEN[open] = *Node; //将其取出放入OPEN
open++;
}
for (i = inList - 1; i <= close - 1; i++) //将其在CLOSE中释放
{
CLOSE[i] = CLOSE[i + 1];
}
close--;
}
}
/*
寻找最佳路径函数
返回 最后的节点Node
*/
ENode* Search()
{
int* status;
int i, j;
ENode* Temp;
while (1) //一直循环知道找到解结束
{
Temp = new ENode;
for (i = open - 1; i > 0; i--) //用冒泡排序给OPEN表里面的节点按耗散值进行排序
{
for (j = 0; j < i; j++)
{
if (OPEN[j].F > OPEN[j + 1].F)
{
*Temp = OPEN[j + 1];
OPEN[j + 1] = OPEN[j];
OPEN[j] = *Temp;
}
}
}
Node = new ENode;
*Node = OPEN[0]; //从OPEN表中取出第一个元素(F值最小)进行扩展
if (!CountH(Node->status)) //判断该节点是否是目标节点,若是,则不在位的将牌数为0,算法结束
{
break;
}
Temp = Node;
CLOSE[close] = *Node; //将扩展过的节点放入CLOSE
close++;
for (i = 0; i <= open - 1; i++) //将扩展的节点从OPEN中释放
{
OPEN[i] = OPEN[i + 1];
}
open--;
if ((Temp->Zero) % 3 >= 1) //如果能左移,则进行左移创造新结点
{
Node = new ENode; //创造新结点
status = Left(Temp->status, Temp->Zero); //得到新的状态
Node = ENodeInit(status, Temp->Zero - 1, (Temp->G) + 1, Temp, 1); //初始化新结点
ExistAndOperate(Node); //判断子节点是否在OPEN或CLOSE中,并进行对应的操作
}
if ((Temp->Zero) % 3 <= 1) //如果能右移,则进行右移创造新结点
{
Node = new ENode;
status = Right(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero + 1, (Temp->G) + 1, Temp, 2);
ExistAndOperate(Node);
}
if (Temp->Zero >= 3) //如果能上移,则进行上移创造新结点
{
Node = new ENode;
status = Up(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero - 3, (Temp->G) + 1, Temp, 3);
ExistAndOperate(Node);
}
if (Temp->Zero <= 5) //如果能下移,则进行下移创造新结点
{
Node = new ENode;
status = Down(Temp->status, Temp->Zero);
Node = ENodeInit(status, Temp->Zero + 3, (Temp->G) + 1, Temp, 4);
ExistAndOperate(Node);
}
if (open == 0) //如果open=0, 证明算法失败, 没有解
return NULL;
}
return Node;
}
/*
展示具体步骤
返回 NULL
*/
void ShowStep(ENode* Node)
{
int STEP[MAXSTEPSIZE];
int STATUS[MAXSTEPSIZE][9];
int step = 0;
int i, j;
int totalStep = Node->G;
while (Node)
{
STEP[step] = Node->step;
for (i = 0; i <= 8; i++)
{
STATUS[step][i] = Node->status[i];
}
step++;
Node = Node->Parent;
}
cout << "----------------------" << endl;
cout << totalStep << endl;
cout << "----------------------" << endl;
for (i = step - 1; i >= 0; i--)
{
if (STEP[i] == 1)
cout << "left";
else if (STEP[i] == 2)
cout << "right";
else if (STEP[i] == 3)
cout << "up";
else if (STEP[i] == 4)
cout << "down";
else if (STEP[i] == 0)
cout << "START";
cout << " ";
}
cout << endl << "----------------------" << endl;
for (i = step - 1; i >= 0; i--)
{
for (j = 0; j <= 8; j++)
{
cout << STATUS[i][j];
if (j == 2 || j == 5 || j == 8)
cout << endl;
else
cout << " ";
}
cout << "----------------------" << endl;
}
}
/*
主函数
返回 0
*/
int main()
{
int fstatus[9];
int i;
ENode* FNode;
ENode* EndNode;
for (i = 0; i <= 8; i++) //输入初始状态
{
cin >> fstatus[i];
}
for (i = 0; i <= 8; i++) //判断0节点位置
{
if (fstatus[i] == 0)
break;
}
FNode = ENodeInit(fstatus, i, 0, NULL, 0); //获得初始节点
OPEN[open] = *FNode; //将初始节点放入OPEN中
open++;
EndNode = Search(); //寻找最佳路径
if (!EndNode)
cout << "无解" << endl;
else
ShowStep(EndNode); //展示步骤
return 0;
}
2.6程序运行截图
2.7算法复杂度分析
时间复杂度最坏为O(n!)
空间复杂度主要受九宫格内的数据量决定,最好情况下,只需存储最佳路径,故空间复杂度为O(n),最坏情况下,需要存储所有数据的全部可能情况,故空间复杂度为O(n!)。n为格内数据量。
2.8 总结与反思
本次问题较上一个实验较难,A星算法对于我来说有些困难,在经历老师讲解和不断尝试后本人对A星算法的掌握和理解,通过此次实验认识到计算机是一个需要不断实践的学科,需要不厌其烦的尝试才能取得进步
实验三 基于二叉排序树的低频词过滤系统
3.1 实验内容
对于一篇给定的英文文章,分别利用线性表和二叉排序树来实现单词频率的统计,实现低频词的过滤,并比较两种方法的效率。
3.2 实验要求
1. 读取英文文章文件(InFile.txt),识别其中的单词。
2. 分别利用线性表和二叉排序树构建单词的存储结构。当识别出一个单词后,若线性表或者二叉排序树中没有该单词,则在适当的位置上添加该单词;若该单词已经被识别,则增加其出现的频率。
3. 统计结束后,删除出现频率低于五次的单词,并显示该单词和其出现频率。
4.其余单词及其出现频率按照从高到低的次序输出到文件中(OutFile.txt),同时输出用两种方法完成该工作所用的时间。
5.计算查找表的ASL值,分析比较两种方法的效率。
3.3 程序代码
#include<iostream>
using namespace std;
#include<stdio.h>
#include<string.h>//字符串比对
#include<string>
#include<fstream>//导入导出
#include<vector>
#include<ctime>//计时函数
#include <iomanip>
#define MAXSIZE 1000
typedef struct
{
char word[20];
int count;
}danci;
//线性表的存储表示
typedef struct
{
danci* a;
int length;
}SqList;
//线性表的初始化
void InitList(SqList& L)
{
L.a = new danci[MAXSIZE];
if (!L.a)
cout << "存储空间分配失败!" << endl;
else
L.length = 0;
}
//比对重复计数
void jishu(SqList& L, danci e)
{
int i;
for (i = 1; i <= L.length; i++)
{
if (strcmp(L.a[i].word, e.word) == 0)
{
L.a[i].count++;
break;
}
}
if (L.length == 0 || i == L.length + 1)
{
L.length++;
int j = L.length;
L.a[j] = e;
}
}
//输入数据
void CreateList_text(SqList& L) {
int K;
FILE* fp;
char ch;
danci e;
fp = fopen("D:\\Infile.txt", "r");
while (!feof(fp))
{
ch = getc(fp);//获取当前字符
if (ch == ' ' || ch == 10 || ch == 44 || ch == 46 || ch == '。')
{//ASCLL码中10为换行符
continue;
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))//发现一个单词
{
K = 0;
e.count = 1;
while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == 39) || ch == '-')
{
if (ch >= 'A' && ch <= 'Z')
{
ch += 32;//转换成小写
}
e.word[K++] = ch;//把当前字母存入数组
ch = getc(fp);
}
e.word[K++] = '\0';//结束标志\0
}
jishu(L, e);
}
}
//显示函数
void display(SqList& L)
{
int i;
cout << "出现次数大于五次的单词" << endl;
cout << "单词" << setw(15) << "数量" << setw(15) << endl;
for (i = 1; i <= L.length; i++)
{
cout << L.a[i].word << setw(15) << L.a[i].count << setw(15) << endl;
}
}
//判断出现次数小于5
void count_five(SqList& L)
{
int i, n = 1;
cout << "出现次数小于五次的单词" << endl;
cout << setw(15) << setw(15) << endl;
for (i = L.length; i > 0; i--)
{
if (L.a[i].count < 5)
{
cout << L.a[i].word << setw(15) << L.a[i].count << setw(15) << endl;
for (int j = i; j <= L.length - 1; j++)
{
L.a[j] = L.a[j + 1];
}
--L.length;
}
}
}
//根据count排序
void sort(SqList& L)
{
int i, j;
for (i = 2; i <= L.length; ++i)
if (L.a[i].count > L.a[i - 1].count)
{
L.a[0] = L.a[i];
L.a[i] = L.a[i - 1];
for (j = i - 2; L.a[0].count > L.a[j].count; --j)
L.a[j + 1] = L.a[j];
L.a[j + 1] = L.a[0];
}
}
//输出到文件
void output(SqList& L)
{
ofstream outfile;
outfile.open("OutFile.txt");
outfile << "出现次数大于5的单词:\n";
outfile << "单词" << '\t' << "次数" << endl;
for (int i = 1; i <= L.length; i++)
{
outfile << L.a[i].word << '\t' << L.a[i].count << endl;
}
outfile.close();
}
//二叉排序树的存储表示
typedef struct BSTNode {
danci b; //单词出现频率
struct BSTNode* lchild, * rchild;
} BSTNode, * BSTree;
void InsertBST(BSTree& T, danci e)
{
if (!T)
{
BSTree S = (BSTree)malloc(sizeof(BSTNode));
S->b = e;
S->lchild = S->rchild = NULL;
T = S;
}
else if (strcmp(e.word, T->b.word) < 0)
{
InsertBST(T->lchild, e);
}
else if (strcmp(e.word, T->b.word) > 0)
{
InsertBST(T->rchild, e);
}
else if (strcmp(e.word, T->b.word) == 0)
{
T->b.count++;
}
}
//获取单词
void getdanci(BSTree& T)
{
T = NULL;
int K;
FILE* fp;
char ch;
danci e;
fp = fopen("D:\\Infile.txt", "r");
while (!feof(fp))
{
ch = getc(fp);//获取当前字符
if (ch == ' ' || ch == 10 || ch == 44 || ch == 46 || ch == '。')
{//ASCLL码中10为换行符
continue;
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))//发现一个单词
{
K = 0;
e.count = 1;
while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == 39 || ch == '-')
{
if (ch >= 'A' && ch <= 'Z')
{
ch += 32;//转换成小写
}
e.word[K++] = ch;//把当前字母存入数组
ch = getc(fp);
}
e.word[K++] = '\0';//结束标志\0
}
InsertBST(T, e);
}
}
//输出显示二叉树(中序遍历)
void MidBST(BSTree& T)
{
if (T != NULL)
{
MidBST(T->lchild);
cout << T->b.word << setw(15) << T->b.count << setw(15) << endl;
MidBST(T->rchild);
}
}
void Insert(BSTree& S, danci e)
{
if (!S)
{
BSTree W = (BSTree)malloc(sizeof(BSTNode));
W->b = e;
W->lchild = W->rchild = NULL;
S = W;
}
else if (e.count >= S->b.count)
{
Insert(S->lchild, e);
}
else if (e.count < S->b.count)
{
Insert(S->rchild, e);
}
}
//二叉排序树的删除
void SerachBST(BSTree& T, BSTree& S)
{
if (T)
{
SerachBST(T->lchild, S);
if (T->b.count >= 5)
{
danci e;
e = T->b;
Insert(S, e);
}
if (T->b.count < 5)
{
cout << T->b.word << setw(15) << T->b.count << setw(15) << endl;
}
SerachBST(T->rchild, S);
}
}
void shuchu(BSTree& S)
{
if (S != NULL)
{
shuchu(S->lchild);
ofstream outfile;
outfile.open("OutFile.txt", ios::app);
outfile << S->b.word << '\t' << S->b.count << endl;
outfile.close();
shuchu(S->rchild);
}
}
void menu()
{
cout << "1、线性表" << endl;
cout << endl;
cout << "2、二叉排序树" << endl;
cout << endl;
cout << "3、退出系统" << endl;
cout << endl;
}
void menu1() {
cout << "1、连续执行至完毕" << endl;
cout << endl;
cout << "2、显示执行时间" << endl;
cout << endl;
cout << "3、单步执行:识别并统计单词" << endl;
cout << endl;
cout << "4、单步执行:删除并显示出现频率低的单词" << endl;
cout << endl;
cout << "5、单步执行:输出其余单词及其频率" << endl;
cout << endl;
cout << "6、单步执行:计算并输出ASL值" << endl;
cout << endl;
cout << "7、返回主菜单" << endl;
cout << endl;
}
int main()
{
while (1)
{
menu();
string key;
cout << "请选择需要执行的操作:";
cin >> key;
system("pause");
system("cls");
if (key != "1" && key != "2" && key != "3")
{
cout << "输入的操作不存在,请重新输入!" << endl;
}
if (key == "1")
{
while (1)
{
SqList L;
menu1();
string n;
cout << "请选择需要执行的操作:";
cin >> n;
if (n == "1")
{
InitList(L);
CreateList_text(L);
sort(L);
count_five(L);
display(L);
output(L);
cout << "已输出到文件夹!" << endl;
}
if (n == "2") {
clock_t start, finish;
start = clock();
InitList(L);
CreateList_text(L);
count_five(L);
sort(L);
display(L);
output(L);
cout << "已输出到文件夹!" << endl;
finish = clock();
int time = finish - start;
cout << "运行的时间为" << time << "毫秒" << endl;
}
if (n == "3")
{
InitList(L);
CreateList_text(L);
cout << "已统计完成!" << endl;
}
if (n == "4")
{
count_five(L);
}
if (n == "5")
{
sort(L);
display(L);
output(L);
cout << "已输出到文件夹!" << endl;
}
if (n == "6")
{
cout << "暂无此操作!" << endl;
}
if (n == "7") { system("cls"); break; }
system("pause");
system("cls");
}
}
if (key == "2")
{
while (1)
{
BSTree T, S;
menu1();
string n;
cout << "请选择需要执行的操作:";
cin >> n;
if (n == "1")
{
T = NULL;
S = NULL;
getdanci(T);
cout << "出现次数小于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
SerachBST(T, S);
cout << "出现次数大于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
MidBST(S);
ofstream outfile;
outfile.open("OutFile.txt");
outfile << "出现次数大于5的单词:" << endl;
outfile << "单词" << '\t' << "次数" << endl;
outfile.close();
shuchu(S);
}
if (n == "2")
{
clock_t start, finish;
start = clock();
T = NULL;
S = NULL;
getdanci(T);
cout << "出现次数小于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
SerachBST(T, S);
cout << "出现次数大于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
MidBST(S);
ofstream outfile;
outfile.open("OutFile.txt");
outfile << "出现次数大于5的单词:" << endl;
outfile << "单词" << '\t' << "次数" << endl;
outfile.close();
shuchu(S);
finish = clock();
int time = finish - start;
cout << "运行的时间为" << time << "毫秒" << endl;
}
if (n == "3")
{
T = NULL;
S = NULL;
getdanci(T);
cout << "已统计完成!" << endl;
}
if (n == "4")
{
cout << "出现次数小于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
SerachBST(T, S);
}
if (n == "5")
{
cout << "出现次数大于5的单词:" << endl;
cout << setw(15) << setw(15) << endl;
MidBST(S);
ofstream outfile;
outfile.open("OutFile.txt");
outfile << "出现次数大于5的单词:" << endl;
outfile << "单词" << '\t' << "次数" << endl;
outfile.close();
shuchu(S);
cout << "已输出到文件!" << endl;
}
if (n == "6")
{
cout << "暂无此操作!" << endl;
}
if (n == "7") { system("cls"); break; }
system("pause");
system("cls");
}
}
if (key == "3")
{
break;
}
}
return 0;
}
3.4 运行界面