数据结构课程设计

目录

实验一  图书信息管理系统的设计与实现

1.1实验目的

1.2实验内容

1.3 实验要求

1.4 实验流程图

1.5 算法的设计与分析

1.5.1菜单界面

1.5.2结构体定义

1.5.3 各种基本操作的函数定义

查找最喜欢的书籍操作

输入操作

输出操作

插入操作

删除操作

按照价格降序排列

查找最贵书籍操作

修改书籍价格操作

主函数

1.6 完整代码

方法一

方法二

1.7 程序运行结果截图(部分功能)

1.8 时间复杂度分析

1.9总结与反思

实验二  隐式图的搜索问题

2.1实验内容

2.2实验所运用的知识

2.2.1  A※算法

2.2.2  A※算法详解

 评价函数:f(n)=g(n)+h(n)

 算法思路

 启发式搜索策略

2.3 流程图

2.4算法设计与分析

结构体定义和三个估值函数的建立

open表和close表的建立

寻找最佳路径函数

主函数

2.5 完整代码

2.6程序运行截图

2.7算法复杂度分析

2.8 总结与反思

             实验三    基于二叉排序树的低频词过滤系统

3.1 实验内容

3.2 实验要求

3.3 程序代码

3.4 运行界面




实验一  图书信息管理系统的设计与实现

1.1实验目的

深入理解数据结构的基本理论,掌握数据存储结构的设计方法,掌握基于数据结构的各种操作的实现方法,训练对基础知识和基本方法的综合运用能力,增强对算法的理解能力,提高软件设计能力。在实践中培养独立分析问题和解决问题的作风和能力。

1.2实验内容

设计并实现一个图书信息管理系统。根据实验要求设计该系统的菜单和交互逻辑,并编码实现增删改查的各项功能。 该系统至少包含以下功能:

  1. 根据指定图书个数,逐个输入图书信息;
  2. 逐个显示图书表中所有图书的相关信息;
  3. 能根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中指定的位置;
  4. 根据指定的待出库的旧图书的位置,将该图书从图书表中删除;
  5. 能统计表中图书个数;
  6. 实现图书信息表的图书去重;
  7. 实现最爱书籍查询,根据书名进行折半查找,要求使用非递归算法实现,成功返回此书籍的书号和价格;
  8. 图书信息表按指定条件进行批量修改;
  9. 利用快速排序按照图书价格降序排序;
  10. 实现最贵图书的查找;

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 运行界面

 

  • 7
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值