【C++】对文章分词,并对词频用不同排序方法排序,比较各排序算法效率(功能全面,通俗易懂)

news2024/11/23 23:39:07

文章分词

  • 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. 程序具体实现

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

异地组网、网络部署、无线覆盖,贝锐蒲公英一步到位

面对网络架构复杂的企业总部&#xff0c;分散在各地的分支机构&#xff0c;以及出差的远程办公人员&#xff0c;如何才能高效异地组网&#xff1f; 为了确保总部、分部网络实现远程稳定、高速互访&#xff0c;以及远程人员安全访问总部业务系统&#xff0c;基于自研SD-WAN的贝…

elementui el-date-picker禁止选择今年、今天、之前、时间范围限制18个月

1、禁止选择今年之前的所有年份 <el-date-pickerv-if"tabsActive 0":clearable"false"v-model"yearValue"change"yearTimeChange"type"year"placeholder"选择年"value-format"yyyy":picker-options…

手搓数组栈(C语言)

stack.h #pragma once#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> // 支持动态增长的栈 typedef int STDataType; typedef struct Stack {STDataType* a;int top; // 栈顶int capacity; // 容量 }Stack; //…

光伏储能系统的主要作用都有什么?

光伏储能系统&#xff0c;结合了光伏技术和储能技术&#xff0c;已经成为当今可再生能源领域的重要一环。它不仅在电力供应中扮演着关键角色&#xff0c;还在许多其他领域展现出其广泛的应用价值。本文将详细探讨光伏储能系统的主要作用。 首先&#xff0c;光伏储能系统在家庭住…

Java苍穹外卖03-Redis-营业状态-HttpClient-微信小程序开发-微信登录以及浏览

一、Redis入门 1.Redis简介 是对MySQL数据库的补充 2.下载安装 启动redis&#xff1a; 再开一个cmd&#xff1a;连接本地redis数据库 如果想连接其他地方的redis数据库&#xff1a;h为ip&#xff0c;p为端口 a为密码 3.数据类型 哈希适合存储对象&#xff0c;列表适合存储…

【问题实操】银河麒麟高级服务器操作系统实例,CPU软锁报错触发宕机

1.服务器环境以及配置 处理器&#xff1a; Kunpeng 920 内存&#xff1a; 256G DDR4 整机类型/架构&#xff1a; TaiShan 200 (Model 2280) 内核版本 4.19.90-23.8.v2101.ky10.aarch64 2.问题现象描述 两台搭载麒麟v10 sp1的机器均在系统CPU软锁报错时&#xff0c;触…

基于遗传优化算法的TSP问题求解matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于遗传优化算法的TSP问题求解&#xff0c;分别对四个不同的城市坐标进行路径搜索。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 ....…

迅睿CMS图集多文件Files调用指南

在构建企业网站、B2B/B2C商城&#xff0c;或任何功能性质以图片展示为主的平台时&#xff0c;使用多图或图集功能变得至关重要。特别是当展示大量产品的详细视图、项目案例图片&#xff0c;或任何需要以图集形式呈现的内容时&#xff0c;多文件Files功能便发挥着无可替代的作用…

Facebook的语言学:社交媒体如何影响我们的沟通方式

1. 引言 社交媒体已经成为人们日常生活中不可或缺的一部分&#xff0c;而Facebook作为其中最具影响力的平台之一&#xff0c;不仅改变了人们之间的社交方式&#xff0c;也对我们的语言学产生了深远的影响。本文将深入探讨Facebook的语言学特点&#xff0c;以及它如何塑造和改变…

AI大模型探索之路-训练篇4:大语言模型训练数据集概览

系列文章目录&#x1f6a9; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 文章目录 系列文章目录&#x1f6a9;前言一、常用的预训练…

优秀的控制台厂家需要考虑哪些方面

在当今数字化时代&#xff0c;控制台已成为众多行业不可或缺的一部分。面对市场上众多的控制台厂家&#xff0c;如何选择合适的供应商成为了一个重要的问题。本文嘉德立将从需求分析、产品质量、价格、服务、口碑等多个方面&#xff0c;为您详细解析如何选择一家优秀的控制台厂…

珠宝品牌如何借助3D技术,成就营销破局之路?

随着电商的快速发展&#xff0c;一直以实体店销售为主的珠宝行业&#xff0c;也开始向线上销售转型&#xff0c;但珠宝作为客单价较高的商品&#xff0c;在线上销售的过程中&#xff0c;会面临图片展示效果不佳&#xff0c;无法亲身体验佩戴效果等问题。 而3D、VR、AR等技术的出…

数海启航:数学与人工智能的深度交织

在人类文明的长河中&#xff0c;数学始终扮演着探秘未知、构建理论框架的基石角色。随着科技的飞速发展&#xff0c;尤其是人工智能&#xff08;AI&#xff09;的兴起&#xff0c;数学与这一前沿领域的结合愈发紧密&#xff0c;成为推动AI进步的最强引擎。 一、数学&#xff1a…

20232801 2023-2024-2 《网络攻防实践》实践八报告

20232801 2023-2024-2 《网络攻防实践》实践八报告 1.实践内容 1.动手实践任务: 对提供的rada恶意代码样本&#xff0c;进行文件类型识别&#xff0c;脱壳与字符串提取&#xff0c;以获得rada恶意代码的编写作者. 2.动手实践任务二&#xff1a;分析Crackme程序 在WinXP Attac…

自定义一个RedisTemplate

1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis&…

动手学深度学习——矩阵

1. 基本概念 1.1 标量 标量由只有一个元素的张量表示。 所以标量计算与程度开发中的普通变量计算没有差异。 import torchx torch.tensor(3.0) y torch.tensor(2.0)x y, x * y, x / y, x**y(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))1.2 向量 向量泛化自标量…

前端CSS基础11(相对定位,绝对定位,固定定位,粘性定位)

前端CSS基础11&#xff08;相对定位&#xff0c;绝对定位&#xff0c;固定定位&#xff0c;粘性定位&#xff09; CSS相对定位&#xff08;position: relative;&#xff09;相对定位的参考点在哪&#xff1f; CSS绝对定位&#xff08;position: absolute&#xff09;如何设置绝…

数据赋能(71)——数据要素:概念

从这期开始&#xff0c;可能讨论数据相关的更高层次的话题——数据要素。讨论数据要素目的&#xff0c;是为了从一个更为宏观的视野去审视数据及数据赋能。这不仅有助于我们深入理解数据的本质与潜在价值&#xff0c;更能为数据的充分利用与未来发展提供更广阔的视角与思路。 …

公共交通无障碍设施:科技翅膀助力盲人出行新飞跃

在城市的脉络中&#xff0c;公共交通扮演着连接每一个角落的重要角色。然而&#xff0c;对于视力受限的盲人朋友而言&#xff0c;这幅繁忙而复杂的交通网络往往隐藏着诸多不易察觉的障碍。值得庆幸的是&#xff0c;随着公共交通无障碍设施的不断完善&#xff0c;以及高科技辅助…

设计模式 装饰模式

文章目录 装饰模式简介装饰模式结构装饰模式代码 装饰模式简介 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许向现有对象动态添加新功能&#xff0c;而不需要修改其现有代码&#xff0c;并且可以通过组合多个装饰器对象实现多种…