C++初学:C++实现TOPSIS(优劣解距离法)

下面是一篇用 python3 实现TOPSIS法(优劣解距离法)的文章,将作者的案例通过C++实现。
由于精力、能力有限,只编写了前半部分,而对于TOPSIS法的关键,
即权重的确定,还有待进一步探索。

> 原文链接:https://zhuanlan.zhihu.com/p/37738503
> 作者主页:https://www.zhihu.com/people/Suranyi


> main.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

using namespace std;

class item;//item类,存放每个要评价的对象

vector<item> read();//读取出对象、指标构成的矩阵
void orientation(vector<item>& all_items);//正向化
void cost(vector<item>& all_items, int col);//极小型正向化
void bestVal(vector<item>& all_items, int col);//中间型正向化
void section(vector<item>& all_items, int col);//区间型正向化
void show(vector<item>& all_items);//输出矩阵到屏幕
void normalization(vector<item>& all_items);//归一化
void distance(vector<item>& all_items);//计算每个对象与最优方案和最劣方案的距离
void insertCol(vector<item>& all_items);//将每列存放到vector嵌套容器便于求最大最小值

vector<vector<double>> column;//vector嵌套容器

class item {

public:
	item() {
		m_name = "";
		m_nums = 5;
		m_target = vector<double>(5);
	}
	item(string name, int nums) :m_name(name), m_nums(nums) {}
	item(const item& it) {
		m_name = it.m_name;
		m_nums = it.m_nums;
		m_target = it.m_target;
	}

	int getNums() {
		return m_nums;
	}
	string getName() {
		return m_name;
	}
	double getTarget(int index) {
		return m_target[index - 1];
	}
	void reNums(int num) {
		m_nums = num;
	}
	void reName(string name) {
		m_name = name;
	}
	void insertdata(double temp) { //插入指标数据
		m_target.push_back(temp);
	}
	void myprint() {
		cout << m_name << "\t";
		for (vector<double>::iterator it = m_target.begin(); it != m_target.end(); it++) {
			cout.setf(ios::fixed);
			cout.precision(6);
			cout << (*it) << "\t";
		}
	}
	void changeVal(int index, double val) {  //修改指标数据
		m_target[index-1] = val;
	}

private:
	string m_name;
	vector<double> m_target; //存放所有指标数据
	int m_nums;//指标数量
};

int main() {
	
	vector<item> all_items = read();
	orientation(all_items);
	show(all_items);
	normalization(all_items);
	show(all_items);
	distance(all_items);
	show(all_items);

	system("pause");
	return 0;
}
//读取源文件,包括表头
vector<item>  read() {

	cout << "输入行数和列数,列为指标,行为评价对象: ";
	int m = 0, n = 0;
	cin >> m >> n;
	cout << endl;

	fstream file;
	file.open("data.txt", ios::in);//打开数据文件
	if (!file.is_open()) {
		cout << "打开失败!";
		exit(0);
	}

	vector<item> all_items;//vector<item> all_items(m-1);
	vector<item>::iterator it_all;
	//读取文件到每个item类
	string buf;
	char ch;
	getline(file, buf);
	for (int i = 0; i < m - 1; i++) {
		buf = "";
		while ((ch = file.get()) != ' ') {
			buf += ch;
		}
		item temp(buf, n - 1);
		for (int j = 0; j < n - 1; j++) {
			double data;
			file >> data;
			temp.insertdata(data);
		}
		all_items.push_back(temp);
	}
	//读取每列到column
	insertCol(all_items);

	file.close();
	show(all_items);

	cout << endl;
	return all_items;
}
//读取每列到column
void insertCol(vector<item>& all_items) {

	column.clear();
	for (int i = 0; i < all_items[1].getNums(); i++) {
		vector<double> v;
		for (int j = 0; j < all_items.size(); j++) {
			v.push_back(all_items[j].getTarget(i + 1));
		}
		column.push_back(v);
	}

}
//所有指标正向化
void orientation(vector<item>& all_items) {

	int index = all_items[1].getNums();
	cout << "分别输入每个指标的类型,空格隔开:1.极大型 2.极小型 3.区间型 4.中间型  ";
	vector<int> type;//vector<int> type(index)
	for (int i = 0; i < index; i++) {
		int t = 0;
		cin >> t;
		type.push_back(t);
	}

	cout << endl;
	for (int i = 0; i < index; i++) {
		switch (type[i]) {
		case 2: {cost(all_items, i + 1); break; }    //极小型
		case 3: {section(all_items, i + 1); break; } //区间型
		case 4: {bestVal(all_items, i + 1); break; } //中间型
		}
	}

	cout << "指标正向化后的矩阵:" << endl;

}
//极小型指标正向化
void cost(vector<item>& all_items, int col) {

	//double maxVal = *max_element(column[col-1].begin(), column[col - 1].end());
	for (int i = 0; i < all_items.size(); i++) {
		//all_items[i].changeVal(col, maxVal - all_items[i].getTarget(col));
		all_items[i].changeVal(col, (double)1 / all_items[i].getTarget(col));
	}

	insertCol(all_items);

}
//区间型指标正向化
void section(vector<item>& all_items, int col) {

	double a = 0, b = 0, c = 0, d = 0;
	cout << "输入最佳区间:";
	cin >> a >> b;
	cout << "输入最大容忍区间:";
	cin >> c >> d;
	cout << endl;

	double maxVal = *max_element(column[col - 1].begin(), column[col - 1].end());
	double minVal = *min_element(column[col - 1].begin(), column[col - 1].end());
	//double M = max(a - minVal, maxVal - b);

	for (int i = 0; i < all_items.size(); i++) {
		if ((all_items[i].getTarget(col) >= a) && (all_items[i].getTarget(col) <= b)) {
			all_items[i].changeVal(col, 1);
		}
		else if (all_items[i].getTarget(col) < a) {
			all_items[i].changeVal(col, 1 - (a - all_items[i].getTarget(col)) / (a - c)); //a-c、d-b  ==  M
		}
		else if (all_items[i].getTarget(col) > b) {
			all_items[i].changeVal(col, 1 - (all_items[i].getTarget(col) - b) / (d - b));
		}
	}

	insertCol(all_items); //由于正向化对原有数据做出改动,需要重新写入每列到column

}
//中间型指标正向化
void bestVal(vector<item>& all_items, int col) {

	cout << "输入中间值:";
	double val = 0;
	cin >> val;
	cout << endl;

	double maxVal = *max_element(column[col - 1].begin(), column[col - 1].end());
	for (int i = 0; i < all_items.size(); i++) {
		all_items[i].changeVal(col, 1 - (abs(maxVal - all_items[i].getTarget(col))) / maxVal);
	}

	insertCol(all_items);

}
void show(vector<item> & all_items) {

	vector<item>::iterator it_all;
	for (it_all = all_items.begin(); it_all != all_items.end(); it_all++) {
		(*it_all).myprint();
	}

	cout << endl << endl;

}
//归一化指标
void normalization(vector<item>& all_items) {

	int index = all_items[1].getNums();
	vector<vector<double>> temp = column;
	vector<double> sum;//保存每列的和
	//先平方
	for (vector<vector<double>>::iterator it = temp.begin(); it != temp.end(); it++) {
		for (vector<double>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) {
			(*vit) *= (*vit);
		}
	}
	//再求和
	for (int i = 0; i < index; i++) {
		double s = accumulate(temp[i].begin(), temp[i].end(), (double)0);
		sum.push_back(sqrt(s));
	}
	//归一化后重新写入
	for (int i = 0; i < index; i++) {
		for (int j = 0; j < all_items.size(); j++) {
			all_items[j].changeVal(i + 1, all_items[j].getTarget(i + 1) / sum[i]);
		}
	}
	//对column进行相同操作
	int i = 0;
	for (vector<vector<double>>::iterator it = column.begin(); it != column.end(); it++) {
		for (vector<double>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) {
			(*vit) /= sum[i];
		}
		i++;
	}

	cout << "归一化初始矩阵:" << endl;

}

//求解距离
void distance(vector<item>& all_items) {
	
	int index = all_items[1].getNums();
	vector<double> best; //存放最优方案
	vector<double> worst;//存放最劣方案

	for (int i = 0; i < index; i++) {
		double maxVal = *max_element(column[i].begin(), column[i].end());
		double minVal = *min_element(column[i].begin(), column[i].end());
		best.push_back(maxVal);
		worst.push_back(minVal);
	}

	cout << "最优方案: ";

	for (int i = 0; i < index; i++) {
		cout << best[i] << " ";
	}

	cout << endl << "最劣方案: ";

	for (int i = 0; i < index; i++) {
		cout << worst[i] << " ";
	}

	cout << endl << endl;
	vector<double> weight;

	cout << "输入权重矩阵:  ";

	for (int i = 0; i < index; i++) {
		double w = 0;
		cin >> w;
		weight.push_back(w);
	}
	//计算得分
	cout << endl;
	vector<double> result;
	for (int i = 0; i < all_items.size(); i++) {
		double sumBest = 0, sumWorst = 0;
		for (int j = 0; j < index; j++) {
			sumBest += weight[j] * pow((all_items[i].getTarget(j + 1) - best[j]), 2);
			sumWorst += weight[j] * pow((all_items[i].getTarget(j + 1) - worst[j]), 2);
		}
		sumBest = sqrt(sumBest);
		sumWorst = sqrt(sumWorst);
		result.push_back(sumWorst / (sumBest + sumWorst));
		all_items[i].insertdata(result[i]);
	}

	cout << "最终结果及得分:" << endl;

}
数据

数据

运行结果

结果

原作者运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伯明翰谢老二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值