【C++】对文章分词,并对词频用不同排序方法排序,比较各排序算法效率

文章分词

  • 1.问题描述
  • 2.需求分析
  • 3.概要设计
    • 3.1 主程序流程
    • 3.2 函数调用关系
  • 4.主函数实现
    • 4.1 main.h
    • 4.2 main.cpp
  • 5. 函数实现
    • 5.1 processDic函数
    • 5.2 forwardMax函数
    • 5.3 countWordFreq函数
    • 5.4 quickResult函数
    • 5.5 其它排序算法效率获取如法炮制,不具体呈现,而只呈现排序算法
    • 5.6 bubbleSort函数
    • 5.7 insertSort函数
    • 5.8 mergeSort函数
    • 5.9 heapSort函数
  • 6. 使用说明
  • 7. 程序具体实现

1.问题描述

中文自然语言处理中,分词是对文本进行分析的最基础工作。现有一段文章,要求对文章进行分词并且对词按词频进行排序。

基本要求:

查找并下载中文词典,根据该词典,对给出的3年内政府工作报告等文章,统计该文本的词频,分析近3年政府工作报告中最高词频的变化。 用快速排序,冒泡排序两种方法对词频进行排序,并保存在不同的文件中。

提高要求:

在基本要求完成的基础上,用直接插入排序、用归并排序、堆排序对词频进行排序,给出效率对比结果,包括时间效率和空间效率,并保存在不同文件中。 分析不同词频情况下(例如正序、逆序、随机)上述几种排序算法的效率。

2.需求分析

软件的基本功能:

根据本地中文词典对给定的文章进行分词,并统计词频。用快速排序,冒泡排序对词频进行排序,并将排序结果保存在不同文件中。再用直接插入排序、归并排序、堆排序对词频进行排序,并对这五种排序算法的时间效率和空间效率进行比较,分析不同词频情况下排序算法的效率,将对比结果保存在不同文件中。

输入/输出形式:

用户可以通过文件进行操作。程序将输出分词结果、词频统计结果、排序结果以及排序算法的效率对比结果到不同文件中。

输入形式:

在“文章输入”文件中输入文章内容。

输出形式:

将分词结果、词频统计结果、排序结果以及排序算法的效率对比结果输出到不同文件中。
测试数据要求:用户可以输入包含大量文本的文章,以及具有不同词频情况的测试数据,用于测试排序算法的效率和准确性。

3.概要设计

3.1 主程序流程

主程序流程图

3.2 函数调用关系

函数调用关系

4.主函数实现

4.1 main.h

#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
#define ERROR cerr << "Open error !" << endl; exit(0);

//词语结构
struct Word
{
	string word;   //词语
	int sum;       //频率
};

extern int maxLen;     //单个词语最大长度
extern int totalWord;  //存储词语总个数
extern unordered_map<string, int> hashMap;   //存储词语和频率

void processDic(string _inFile);
void forwardMax(string _inFile, string _outFile);
void countWordFreq(Word* arr, string _outFile);
void reversequickSort(Word* r, int low, int high);
void quickResult(Word* arr, string _outFile1, string _outFile2, string _outFile3);
void bubbleResult(Word* arr, string _outFile1, string _outFile2, string _outFile3);
void insertResult(Word* arr, string _outFile1, string _outFile2);
void mergeResult(Word* arr, string _outFile1, string _outFile2);
void heapResult(Word* arr, string _outFile1, string _outFile2);

4.2 main.cpp

#include "main.h"

int maxLen = 0;
int totalWord = 0;
unordered_map<string, int> hashMap;

int main()
{
	cout << "正在运行中..." << endl;
	 
	processDic("中文词典.txt");
	forwardMax("文章输入.txt", "分词结果.txt");

	Word* arr = new Word[totalWord];

	countWordFreq(arr, "词频统计.txt");
	quickResult(arr, "快速排序结果.txt", "时间效率对比结果.txt", "空间效率对比结果.txt");
	bubbleResult(arr, "冒泡排序结果.txt", "时间效率对比结果.txt", "空间效率对比结果.txt");
    insertResult(arr, "时间效率对比结果.txt", "空间效率对比结果.txt");
	mergeResult(arr, "时间效率对比结果.txt", "空间效率对比结果.txt");
	heapResult(arr, "时间效率对比结果.txt", "空间效率对比结果.txt");
	
	system("cls");
	cout << "已完成!" << endl;
	delete[] arr;

	return 0;
}

5. 函数实现

5.1 processDic函数

用于处理词典,将词典词语存储在哈希表中,并统计词语的最大长度。

//过滤非中文字符
bool Check(string s)
{
	if (s[0] >= 0 && s[0] < 256)
	{
		return false;
	}
	else
	{
		return true;
	}
}

//处理词典
void processDic(string _inFile)
{
	ifstream inFile(_inFile);

	if (!inFile)
	{
		ERROR;
	}

	string str;

	while (inFile >> str)
	{
		if (Check(str))
		{
			if (str.size() > maxLen)
			{
				maxLen = str.size();
			}

			hashMap[str] = 0;
		}	
	}

	inFile.close();
	inFile.clear();
}

5.2 forwardMax函数

用正向最大匹配算法对输入的文章进行分词,在查找过程中统计文章词语数量,便于动态申请数组空间,并统计词频,最后将分词结果保存在文件中。

//文章分词
//正向最大匹配算法
void forwardMax(string _inFile, string _outFile)
{
	ifstream inFile(_inFile);
	ofstream outFile(_outFile);

	if (!inFile || !outFile)
	{
		ERROR;
	}

	ostringstream temp;
	temp << inFile.rdbuf();
	string textTmp = temp.str();

	int Begin = 0, End = textTmp.size();

	while (Begin < End)
	{
		string str;
		int num;

		for (num = min(maxLen, (End - Begin)); num > 0; num--)
		{
			str = textTmp.substr(Begin, num);

			if (hashMap.find(str) != hashMap.end())
			{
				if (hashMap[str] == 0)
				{
					totalWord++;
				}

				outFile << str;
				Begin += num;
				hashMap[str]++;
				break;
			}
		}

		if (num == 0)
		{
			outFile << textTmp.substr(Begin, 1);
			Begin += 1;
		}

		outFile << "/";
	}

	inFile.close();
	inFile.clear();
	outFile.close();
	outFile.clear();
}

5.3 countWordFreq函数

用于统计文章词频,并将统计结果保存在文件中。

//统计词频
void countWordFreq(Word* arr, string _outFile)
{
	ofstream outFile(_outFile);

	if (!outFile)
	{
		ERROR;
	}

	int i = 0;

	for (unordered_map<string, int>::iterator it = hashMap.begin(); it != hashMap.end(); it++)
	{
		if (it->second > 0)
		{
			arr[i].word = it->first;
			arr[i].sum = it->second;
			i++;

			outFile << it->first << "\t\t出现次数:\t" << it->second << endl;
		}
	}

	outFile.close();
	outFile.clear();
}

5.4 quickResult函数

实现对随机词频、正序词频、逆序词频的快速排序,并将排序结果,排序时间、空间效率保存在不同文件中。

double quickMemory = 0;

//快速排序
int Part(Word* r, int low, int high)
{
	int i = low, j = high;

	while (i < j)
	{
		while (i < j && r[i].sum >= r[j].sum)
		{
			j--;
		}

		if (i < j)
		{
			swap(r[i], r[j]);
			i++;
		}

		while (i < j && r[i].sum >= r[j].sum)
		{
			i++;
		}

		if (i < j)
		{
			swap(r[i], r[j]);
			j--;
		}
	}

	quickMemory += sizeof(int) * 2;
	return i;
}

void quickSort(Word* r, int low, int high)
{
	if (low < high)
	{
		int pivot = Part(r, low, high);
		quickSort(r, low, pivot - 1);
		quickSort(r, pivot + 1, high);
	}

	quickMemory += sizeof(int);
}

//快速排序结果
void quickResult(Word* arr, string _outFile1, string _outFile2, string _outFile3)
{
	Word* r = new Word[totalWord];
	clock_t start1, end1, start2, end2, start3, end3;

	copy(arr, arr + totalWord, r);

	ofstream outFile1(_outFile1);
	ofstream outFile2(_outFile2);
	ofstream outFile3(_outFile3);

	if (!outFile1 || !outFile2 || !outFile3)
	{
		ERROR;
	}

	start1 = clock();
	quickSort(r, 0, totalWord - 1);
	end1 = clock();

	outFile3 << "排序方法\t\t所占内存大小\n\n";
	outFile3 << "快速排序\t\t" << quickMemory / 1024 << "KB" <<  endl << endl;	
	
	start2 = clock();
	quickSort(r, 0, totalWord - 1);
	end2 = clock();

	reversequickSort(r, 0, totalWord - 1);

	start3 = clock();
	quickSort(r, 0, totalWord - 1);
	end3 = clock();
	
	for (int i = 0; i < totalWord; i++)
	{
		outFile1 << r[i].word << "\t\t出现次数:\t" << r[i].sum << endl;
	}

	outFile2 << "排序方法\t\t随机词频用时\t\t正序词频用时\t\t逆序词频用时\n\n";
	outFile2 << "快速排序\t\t" << double(end1 - start1) / CLOCKS_PER_SEC << "s\t\t\t"
		<< double(end2 - start2) / CLOCKS_PER_SEC << "s\t\t\t" << double(end3 - start3) / CLOCKS_PER_SEC << "s\n\n";
	
	delete[] r;
	outFile1.close();
	outFile1.clear();
	outFile2.close();
	outFile2.clear();
	outFile3.close();
	outFile3.clear();
}

5.5 其它排序算法效率获取如法炮制,不具体呈现,而只呈现排序算法

5.6 bubbleSort函数

void bubbleSort(Word* r, int n)
{
	int exchange = n;

	while (exchange != 0)
	{
		int bound = exchange;
		exchange = 0;

		for (int i = 1; i < bound; i++)
		{
			if (r[i - 1].sum < r[i].sum)
			{
				swap(r[i - 1], r[i]);
				exchange = i;
			}
		}
	}

	bubbleMemory += sizeof(int) * 3;
}

5.7 insertSort函数

//直接插入排序
void insertSort(Word* r, int n)
{
	for (int i = 1; i < n; i++)
	{
		Word temp = r[i];
		int j;

		for (j = i; j > 0 && r[j - 1].sum < temp.sum; j--)
		{
			r[j] = r[j - 1];
		}

		r[j] = temp;
	}

	insertMemory += sizeof(int) * 2 + sizeof(Word);
}

5.8 mergeSort函数

//归并排序
void Merge(Word* a, Word* b, int low, int mid, int high)
{
	int i = low, j = mid + 1, k = 0;

	while (i <= mid && j <= high)
	{
		if (a[i].sum >= a[j].sum)
		{
			b[k++] = a[i++];
		}
		else
		{
			b[k++] = a[j++];
		}
	}

	while (i <= mid)
	{
		b[k++] = a[i++];
	}

	while (j <= high)
	{
		b[k++] = a[j++];
	}

	k = 0;

	for (int i = low; i <= high; i++)
	{
		a[i] = b[k++];
	}

	mergeMemory +=  sizeof(int) * 3;
}

void mergeSort(Word* r1, Word* r2, int low, int high)
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		mergeSort(r1, r2, low, mid);
		mergeSort(r1, r2, mid + 1, high);
		Merge(r1, r2, low, mid, high);
	}

	mergeMemory += sizeof(int);
}

5.9 heapSort函数

//堆排序
void Sift(Word* r, int start, int end)
{
	int i = start, j = 2 * start + 1;

	while (j < end)
	{
		if (j + 1 < end && r[j].sum > r[j + 1].sum)
		{
			j++;
		}

		if (r[i].sum < r[j].sum)
		{
			break;
		}
		else
		{
			swap(r[i], r[j]);
			i = j;
			j = i * 2 + 1;
		}
	}

	heapMemory += sizeof(int) * 2;
}

void heapSort(Word* r, int n)
{
	for (int i = n / 2 - 1; i >= 0; i--)
	{
		Sift(r, i, n);
	}

	for (int i = n - 1; i > 0; i--)
	{
		swap(r[0], r[i]);
		Sift(r, 0, i);
	}

	heapMemory += sizeof(int);
}

6. 使用说明

在程序文件同一目录下的“文章输入.txt”中输入所要进行操作的文章。
运行程序,待控制台显示由“正在运行中…”转变成“已完成!”时,分词、统计、排序等操作便一并完成,并以文件形式保存在同一目录下,通过文件名称即可查看相应操作结果。

7. 程序具体实现

点击下方链接即可 ^ ^
此为链接,可查看/下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/594258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【链表】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

十二、泛型

这里写自定义目录标题 一、什么是泛型二、为什么需要泛型&#xff1f;三、自定义泛型结构1、泛型类2、泛型方法 四、泛型在继承上的体现五、通配符的使用1、注意点2、有限制的通配符 一、什么是泛型 泛型就是定义类、接口时通过一个标识表示类中某个属性的类型 、方法的返回值…

C#实现简单音乐文件解析播放——Windows程序设计作业2

1. 作业内容 编写一个C#程序&#xff0c;要求实现常见音乐文件的播放功能&#xff0c;具体要求如下&#xff1a;     1). 播放MP3文件&#xff1a; 程序应能够读取MP3文件&#xff0c;并播放其中的音频。     2). 播放OGG文件&#xff1a; 应能够播放ogg文件。     …

学习3:scrapy请求对象、模拟登录、POST请求、管道的使用、crawlspider爬虫类

请求对象 请求对象参数 scrapy.Request(url[],callback,method"GET",headers,body,cookies,meta,dont_filterFalse)callback 表示当前的url响应交给那个函数去处理method 指定请求方式headers 接受一个字典&#xff0c;其中不包括cookiesbody 接收json字符串&#…

OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69) 下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71) 目录 目标 理论 如何消除傅里叶域中的周期性噪声&#xff1f; 源代码 解释 结果 目…

IDEA--debug

1. 单点调试的三个级别 Step into&#xff1a;在单步执行时&#xff0c;遇到子函数就进入并且继续单步执行。Step over&#xff1a;在单步执行时&#xff0c;在函数内遇到子函数时不会进入子函数内单步执行&#xff0c;而是将子函数整个执行完再停止&#xff0c;也就是把子函数…

用树莓派2B当web服务器

树莓派2&#xff0c;卡片大小&#xff0c;arm 32位cpu&#xff0c;512G内存。我找了一下购买记录&#xff0c;2013年12月15日买的。带网线接头。属于树莓派2B。以前下载的操作系统还在。是2014年的操作系统&#xff0c;文件名是&#xff1a;2014-09-09-wheezy-raspbian_shumeip…

C语言之整形提升和算术转换

目录 前言 一、整形提升 二、算术转换 总结 前言 本文主要介绍C语言中的整形提升和算术转换的概念和意义&#xff0c;以及例题帮助理解&#xff0c;了解之后&#xff0c;我们就能知道在C语言中&#xff0c;字符型变量如何计算以及如果变量的类型、字节大小不一致的情况下&am…

前端工程化06-JavaScript模块化CommonJS规范ES Module

7、JavaScript模块化 在js开发中&#xff0c;他并没有拆分的概念&#xff0c;并不像java一样他可以拆分很多的包&#xff0c;很多的类&#xff0c;像搭积木一样完成一个大型项目的开发&#xff0c;所以js在前期的时候并不适合大型后端的项目开发&#xff0c;但是这些问题在后来…

Android 10.0 Launcher3 app页面调整workspace边距app行距变小功能实现

1.前言 在10.0的系统rom定制化开发中,在launcher3的一些开发定制功能中,在对于大分辨率比如1600*2560的设备进行开发的时候, 会在竖屏的时候,在默认7*4的布局的时候,显得行距有点宽,这样就需要调整整个CellLayout的上下左右边距,然后就 会显得行距会小一点,接下来具体…

ASP.NET网上书店

摘要 本设计尝试用ASP.NET在网络上架构一个电子书城&#xff0c;以使每一位顾客不用出门在家里就能够通过上网来轻松购书。本文从理论和实践两个角度出发&#xff0c;对一个具有数据挖掘功能电子书城进行设计与实现分析。论文首先较为详尽地介绍了面向对象分析与设计的有关概念…

基于Springboot的房屋租赁管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的房屋租赁管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

图中有几个三角形

让我们先把三角形进行分类&#xff1a;1块组成的三角形、2块组成的三角形、依此类推。 1块组成的三角形有4个&#xff1a; 2块组成的三角形有&#xff1a;12,13,14,23,24,34.其中&#xff0c;14&#xff0c;23构不成三角形. 3块组成的三角形有&#xff1a;123,124,134,234。但…

贪心算法(活动选择、分数背包问题)

一、贪心算法 贪心算法是指&#xff1a;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择&#xff0c;而不从整体最优考虑&#xff0c;做出的仅是在某种意义上的局部最优解。 …

流畅的Python阅读笔记

五一快乐的时光总是飞快了&#xff0c;不知多久没有拿起键盘写文章了&#xff0c;最近公司有Python的需求&#xff0c;想着复习下Python吧&#xff0c;然后就买了本Python的书籍 书名&#xff1a; 《流畅的Python》 下面是整理的一个阅读笔记&#xff0c;大家自行查阅&#xf…

Python 全栈系列241 GFGo Lite迭代

说明 随着整个算网开发逐渐深入&#xff0c;各个组件、微服务的数量、深度在不断增加。由于算网是个人项目&#xff0c;我一直按照MVP(Minimum Viable Product )的原则在推进。由于最初的时候对架构、算法和业务的理解并没有那么深刻&#xff0c;所以MVP的内容还是在不断变化&…

选择深度学习框架:TensorFlow 2 vs PyTorch

TensorFlow 2 vs PyTorch 选择深度学习框架&#xff1a;TensorFlow 2 vs PyTorchTensorFlow 2概述TensorFlow 2的优点TensorFlow 2的缺点 PyTorch概述PyTorch的优点PyTorch的缺点 选择建议对于选择困难症的人&#xff0c;我给你们的答案——PyTorch选择理由&#xff1a;结论&am…

数据结构(C):玩转链表

&#x1f37a;0.前言 言C之言&#xff0c;聊C之识&#xff0c;以C会友&#xff0c;共向远方。各位博友的各位你们好啊&#xff0c;这里是持续分享数据结构知识的小赵同学&#xff0c;今天要分享的数据结构知识是链表&#xff0c;在这一章&#xff0c;小赵将会向大家展开聊聊链表…

常用语音识别开源四大工具:Kaldi,PaddleSpeech,WeNet,EspNet

无论是基于成本效益还是社区支持&#xff0c;我都坚决认为开源才是推动一切应用的动力源泉。下面推荐语音识别开源工具&#xff1a;Kaldi&#xff0c;Paddle&#xff0c;WeNet&#xff0c;EspNet。 1、最成熟的Kaldi 一个广受欢迎的开源语音识别工具&#xff0c;由Daniel Pove…

Servlet框架

简介 Servlet是运行在web服务器或应用服务器上的程序&#xff0c;他是作为来自web浏览器或其他http客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。 使用Servlet可以手机来自网页表单的用户输入&#xff0c;呈现来自数据库或者其他源记录&#xff0c;还可以动态创…