C++ 朴素贝叶斯模型(Naive Bayesian Model,NBM)实现, 西瓜实验数据集 基于周志华老师机器学习

本文主要是介绍C++ 朴素贝叶斯模型(Naive Bayesian Model,NBM)实现, 西瓜实验数据集 基于周志华老师机器学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++ 朴素贝叶斯模型(Naive Bayesian Model,NBM)实现, 西瓜实验数据集 基于周志华老师机器学习

版权声明:本文为博主原创文章,未经博主允许不得转载。

标注

学习朴素贝叶斯算法得了解一些基本知识,比如全概率公式和贝叶斯公式。大学基本都学过不在赘述。

数据样本

编号色泽根蒂敲声纹理脐部触感密度含糖率好瓜
12221310.6970.461
23231310.7440.3761
33221310.6340.2641
42231310.6080.3181
51221310.5560.2151
62121220.4030.2371
73122220.4810.1491
83121210.4370.2111
93132210.6660.0910
102311120.2430.2670
111313110.2450.0570
121223120.3430.0990
132122310.6390.1610
141132310.6570.1980
153121220.360.370
161223110.5930.0420
172232210.7190.1030

表格含义

色泽 1-3代表 浅白 青绿 乌黑
根蒂 1-3代表 稍蜷 蜷缩 硬挺
敲声 1-3代表 清脆 浊响 沉闷
纹理 1-3代表 清晰 稍糊 模糊
脐部 1-3代表 平坦 稍凹 凹陷
好瓜 1代表 是 0 代表 不是

算法定义

朴素贝叶斯算法定义如下:
这里写图片描述
这里写图片描述

代码块

//bayesian.h
#pragma once
//定义训练数据  
#define M 17  
#define N 9  
/*
*色泽 1—3代表 浅白 青绿 乌黑
*根蒂 1-3代表 稍蜷 蜷缩 硬挺
*敲声1-3代表 清脆 浊响 沉闷
*纹理 1-3代表 清晰 稍糊 模糊         
*脐部1-3代表 平坦 稍凹 凹陷          
*触感 1-2 代表 硬滑 软粘            
*好瓜 1代表是 0 代表不是                             
*/  
double A[M][N]= {  {2,2,2,1,3,1,0.697,0.460,1},//  1{3,2,3,1,3,1,0.744,0.376,1},//  2{3,2,2,1,3,1,0.634,0.264,1},//  3{2,2,3,1,3,1,0.608,0.318,1},//  4{1,2,2,1,3,1,0.556,0.215,1},//  5{2,1,2,1,2,2,0.403,0.237,1},//  6{3,1,2,2,2,2,0.481,0.149,1},//  7{3,1,2,1,2,1,0.437,0.211,1},//  8{3,1,3,2,2,1,0.666,0.091,0},//  9{2,3,1,1,1,2,0.243,0.267,0},//  10{1,3,1,3,1,1,0.245,0.057,0},//  11{1,2,2,3,1,2,0.343,0.099,0},//  12{2,1,2,2,3,1,0.639,0.161,0},//  13{1,1,3,2,3,1,0.657,0.198,0},//  14{3,1,2,1,2,2,0.360,0.370,0},//  15{1,2,2,3,1,1,0.593,0.042,0},//  16{2,2,3,2,2,1,0.719,0.103,0} //  17};  struct Px1  
{  double x1;  double y;  double p_x1y;  
};  struct Px2  
{  double x2;  double y;  double p_x2y;  
};  struct Px3  
{  double x3;  double y;  double p_x3y;  
};  
struct Px4  
{  double x4;  double y;  double p_x4y;  
};  
struct Px5  
{  double x5;  double y;  double p_x5y;  
};  
struct Px6  
{  double x6;  double y;  double p_x6y;  
};  
struct Px7  
{  double x7;  double y;  double p_x7y;  
};  
struct Px8  
{  double x8;  double y;  double p_x8y;  
};  
// struct MeAVa 
// {  
//  double mean;  
//  double stdev;  
// };  double p[2];  
Px1 px1[6];  
Px2 px2[6];
Px3 px3[6];
Px4 px4[6];
Px5 px5[6];
Px6 px6[6];
Px7 px7[2];
Px8 px8[2];  //bayesian .cpp
#include "bayesian.h"
#include <iostream>  
#include <set>  
#include <vector>  
#include <numeric>
#include <algorithm>
#include <iomanip>
//#include <math.h>
#include <cmath>
using namespace std;  
//好瓜密度概率计算
double m_MeansAndAver(double x)
{double resultSet[17];double p;for (int i = 0; i < M; i++){resultSet[i]=A[i][6];}double sum = std::accumulate(std::begin(resultSet), std::begin(resultSet)+8, 0.0);double mean=  sum /8; //均值double accum  = 0.0;std::for_each (std::begin(resultSet), std::begin(resultSet)+8, [&](const double d) {accum  += (d-mean)*(d-mean);});double stdev = sqrt(accum/(7)); //方差
//  std::cout<<"--------------------test1-------------------------------"<<stdev<<endl;
//  std::cout<<"均值为"<<mean<<"方差为:"<<stdev<<endl;
//  std::cout<<"--------------test---------------"<<endl;p = (1/(sqrt(2*3.14)*stdev))*exp(-(pow((x-mean),2)/(2*pow(stdev,2))));//px7[0]=p;px7[0].p_x7y=p ;return p;
}
//坏瓜密度概率计算
double m_w_MeansAndAver(double x)
{double resultSet[17];double p;for (int i = 0; i < M; i++){resultSet[i]=A[i][6];}double sum = std::accumulate(std::begin(resultSet)+8, std::end(resultSet), 0.0);double mean=  sum /9; //均值double accum  = 0.0;std::for_each ( std::begin(resultSet)+8,std::end(resultSet), [&](const double d) {accum  += (d-mean)*(d-mean);});double stdev = sqrt(accum/(8)); //方差
//  std::cout<<"--------------------test2-------------------------------"<<stdev<<endl;
//  std::cout<<"均值为"<<mean<<"方差为:"<<stdev<<endl;
//  std::cout<<"--------------test---------------"<<endl;p = (1/(sqrt(2*3.14)*stdev))*exp(-(pow((x-mean),2)/(2*pow(stdev,2))));px7[1].p_x7y=p ;return p;
}
//好瓜含糖量概率计算
double h_MeansAndAver(double x)
{double resultSet[17];double p;for (int i = 0; i < M; i++){resultSet[i]=A[i][7];}double sum = std::accumulate(std::begin(resultSet), std::begin(resultSet)+8, 0.0);double mean=  sum /8; //均值double accum  = 0.0;std::for_each (std::begin(resultSet), std::begin(resultSet)+8, [&](const double d) {accum  += (d-mean)*(d-mean);});double stdev = sqrt(accum/(7)); //方差
//  std::cout<<"--------------------test3--------------------------------"<<stdev<<endl;
//  std::cout<<"均值为"<<mean<<"方差为:"<<stdev<<endl;
//  std::cout<<"--------------test---------------"<<endl;p = (1/(sqrt(2*3.14)*stdev))*exp(-(pow((x-mean),2)/(2*pow(stdev,2))));px8[0].p_x8y=p;return p;
}//坏瓜含糖量概率计算
double h_w_MeansAndAver(double x)
{double resultSet[17];double p;for (int i = 0; i < M; i++){resultSet[i]=A[i][7];}double sum = std::accumulate(std::begin(resultSet)+8, std::end(resultSet), 0.0);double mean=  sum /9; //均值double accum  = 0.0;std::for_each (std::begin(resultSet)+8,  std::end(resultSet), [&](const double d) {accum  += (d-mean)*(d-mean);});double stdev = sqrt(accum/(8)); //方差
//  std::cout<<"--------------------test4--------------------------------"<<stdev<<endl;
//  std::cout<<"均值为"<<mean<<"方差为:"<<stdev<<endl;
//  std::cout<<"--------------test---------------"<<endl;p = (1/(sqrt(2*3.14)*stdev))*exp(-(pow((x-mean),2)/(2*pow(stdev,2))));px8[1].p_x8y=p;return p;
}
//计算先验概率和条件概率  
void calP()  
{//计算先验  //double p[2];  int i, j, k;  multiset<double> m_x1, m_x2,m_x3, m_x4,m_x5, m_x6,m_x7, m_x8, m_y;//多重集容器  multiset<double>::iterator pos1;  set<double> x1, x2,x3, x4,x5, x6,x7, x8, y;//集合容器  set<double>::iterator pos2, pos3;  //运用多重集容器和集合容器  for(i = 0; i < M; i++) {m_x1.insert(A[i][0]);  m_x2.insert(A[i][1]);m_x3.insert(A[i][2]);m_x4.insert(A[i][3]);m_x5.insert(A[i][4]);m_x6.insert(A[i][5]);m_x7.insert(A[i][6]);m_x8.insert(A[i][7]);m_y.insert(A[i][8]);  x1.insert(A[i][0]);  x2.insert(A[i][1]);x3.insert(A[i][2]);x4.insert(A[i][3]);x5.insert(A[i][4]);x6.insert(A[i][5]);x7.insert(A[i][6]);x8.insert(A[i][7]);y.insert(A[i][8]); }  p[0] = m_y.count(1) / (double)M;    //p(Y = 1)  p[1] = m_y.count(0) / (double)M;    //p(Y = 2)  cout << endl << "************先验***********" << endl; 
//p[0]代表好瓜所占的比例  p[1]代表坏瓜所占的比例cout << "p(Y = 1) = " << p[0] << endl;  cout << "p(Y = 0) = " << p[1] << endl; //计算条件概率  cout << endl;  cout << "*********条件概率********" << endl;  //  int px1_num = 3 * 2;  //  int px2_num = 3 * 2;  
//p(x1 | y)概率j=0; for(pos2 = y.begin(); pos2 != y.end(); pos2++)  { for(pos3 = x1.begin(); pos3 != x1.end(); pos3++)  {       px1[j].y = *pos2;  px1[j].x1 = *pos3;  int count_x1y = 0;  for(k = 0; k < M; k++)  {  if(A[k][0] == px1[j].x1 && A[k][8] == px1[j].y)  count_x1y++;  }  px1[j].p_x1y = count_x1y / (double)m_y.count(px1[j].y);//计算p(x1 | y)的概率  j++;  }  }  cout << "p(x1 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px1[j].x1 << " " <<  px1[j].y << " " << px1[j].p_x1y << endl;  }  
//p(x2|y)概率j=0;  for(pos2 = y.begin(); pos2 != y.end(); pos2++)  {  for(pos3 = x2.begin(); pos3 != x2.end(); pos3++)  {  px2[j].y = *pos2;  px2[j].x2 = *pos3;  int count_x2y = 0;  for(k = 0; k < M; k++)  {  if(A[k][1] == px2[j].x2 && A[k][8] == px2[j].y)  count_x2y++;  }  px2[j].p_x2y = count_x2y / (double)m_y.count(px2[j].y);//计算p(x2 | y)的概率  j++;  }  }  cout << "p(x2 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px2[j].x2 << " " <<  px2[j].y << " " << px2[j].p_x2y << endl;  }  //p(x3|y)概率j=0;  for(pos2 = y.begin(); pos2 != y.end(); pos2++)  {  for(pos3 = x3.begin(); pos3 != x3.end(); pos3++)  {  px3[j].y = *pos2;  px3[j].x3 = *pos3;  int count_x3y = 0;  for(k = 0; k < M; k++)  {  if(A[k][2] == px3[j].x3 && A[k][8] == px3[j].y)  count_x3y++;  }  px3[j].p_x3y = count_x3y / (double)m_y.count(px3[j].y);//计算p(x2 | y)的概率  j++;  }  }  cout << "p(x3 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px3[j].x3 << " " <<  px3[j].y << " " << px3[j].p_x3y << endl;  }  
//p(x4|y)概率j=0;  for(pos2 = y.begin(); pos2 != y.end(); pos2++)  {  for(pos3 = x4.begin(); pos3 != x4.end(); pos3++)  {  px4[j].y = *pos2;  px4[j].x4 = *pos3;  int count_x4y = 0;  for(k = 0; k < M; k++)  {  if(A[k][3] == px4[j].x4 && A[k][8] == px4[j].y)  count_x4y++;  }  px4[j].p_x4y = count_x4y / (double)m_y.count(px4[j].y);//计算p(x4 | y)的概率  j++;  }  }  cout << "p(x4 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px4[j].x4 << " " <<  px4[j].y << " " << px4[j].p_x4y << endl;  }  
//p(x5|y)概率j=0;  for(pos2 = y.begin(); pos2 != y.end(); pos2++)  {  for(pos3 = x5.begin(); pos3 != x5.end(); pos3++)  {  px5[j].y = *pos2;  px5[j].x5 = *pos3;  int count_x5y = 0;  for(k = 0; k < M; k++)  {  if(A[k][4] == px5[j].x5 && A[k][8] == px5[j].y)  count_x5y++;  }  px5[j].p_x5y = count_x5y / (double)m_y.count(px5[j].y);//计算p(x5 | y)的概率  j++;  }  }  cout << "p(x5 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px5[j].x5 << " " <<  px5[j].y << " " << px5[j].p_x5y << endl;  }  
//p(x6|y)概率j=0;  for(pos2 = y.begin(); pos2 != y.end(); pos2++)  {  for(pos3 = x6.begin(); pos3 != x6.end(); pos3++)  {  px6[j].y = *pos2;  px6[j].x6 = *pos3;  int count_x6y = 0;  for(k = 0; k < M; k++)  {  if(A[k][5] == px6[j].x6 && A[k][8] == px6[j].y)  count_x6y++;  }  px6[j].p_x6y = count_x6y / (double)m_y.count(px6[j].y);//计算p(x6 | y)的概率  j++;  }  }  cout << "p(x6 | y):" << endl;  for(j = 0; j < 6; j++)  {  cout << px6[j].x6 << " " <<  px6[j].y << " " << px6[j].p_x6y << endl;  }  
//p(x7|y)概率} 
int main()  
{  int i = 0, j = 0;  //输出训练数据  cout << "***********训练数据************" << endl;  for(i = 0; i < M; i++)  {  for(int j = 0; j < N; j++)  {  cout << " "<< A[i][j];  }  cout << endl;  } calP();//计算先验和条件概率  int s_x1, s_x2, s_x3, s_x4, s_x5, s_x6;double  s_x7, s_x8;  double result[2];  int class_y = 1;  cout<< "##########################< 提   示 >##########################"<<endl;cout<<setw(10)<<"色泽"<<setw(10)<<"1-3代表"<<setw(10)<<"浅白"<<setw(10)<<"青绿"<<setw(10)<<"乌黑"<<endl;cout<<setw(10)<<"根蒂"<<setw(10)<<"1-3代表"<<setw(10)<<"稍蜷"<<setw(10)<<"蜷缩"<<setw(10)<<"硬挺"<<endl;cout<<setw(10)<<"敲声"<<setw(10)<<"1-3代表"<<setw(10)<<"清脆"<<setw(10)<<"浊响"<<setw(10)<<"沉闷"<<endl;cout<<setw(10)<<"纹理"<<setw(10)<<"1-3代表"<<setw(10)<<"清晰"<<setw(10)<<"稍糊"<<setw(10)<<"模糊"<<endl;cout<<setw(10)<<"脐部"<<setw(10)<<"1-3代表"<<setw(10)<<"平坦"<<setw(10)<<"稍凹"<<setw(10)<<"凹陷"<<endl;cout<<setw(10)<<"触感"<<setw(10)<<"1-2代表"<<setw(10)<<"硬滑"<<setw(10)<<"软粘"<<endl;cout<<"      密度以及含糖量 0<Xi<1 "<<endl;cout<<"      请按照以上范围输入"<<endl;cout<< "###############################################################"<<endl;/************************************************************************//* 色泽  1-3代表  浅白  青绿  乌黑根蒂  1-3代表  稍蜷  蜷缩  硬挺敲声  1-3代表  清脆  浊响  沉闷纹理  1-3代表  清晰  稍糊  模糊脐部  1-3代表  平坦  稍凹  凹陷触感  1-2代表  硬滑  软粘    好瓜  1代表 是  0 代表  不是                             *//************************************************************************/cout <<endl<< "##########################< 预   测 >##########################"<<endl; cout <<endl<<"Input:";  cin >> s_x1 >> s_x2>> s_x3>> s_x4>> s_x5>> s_x6>> s_x7>> s_x8; cout << "##########<连续属性X7与x8的 p(x7|y)、<p(x8|y)计算结果>##########"<<endl<<endl; cout<<"好瓜密度其概率为:"<<m_MeansAndAver(s_x7)<<endl;//当前密度,在是好瓜的情况下可能发生的概率cout<<"坏瓜密度的概率"<<m_w_MeansAndAver(s_x7)<<endl;//准确cout<<"好瓜其概率为:"<<h_MeansAndAver(s_x8)<<endl;//准确cout<<"好瓜其概率为:"<<h_w_MeansAndAver(s_x8)<<endl<<endl;//准确for(i = 0; i < 2; i++)  {  double s_px_1, s_px_2, s_px_3, s_px_4, s_px_5, s_px_6, s_px_7, s_px_8;  for(j = 0; j < 6; j++)  {  if(s_x1 == px1[j].x1 && px1[j].y == class_y)  s_px_1 = px1[j].p_x1y;  if(s_x2 == px2[j].x2 && px2[j].y == class_y)s_px_2 = px2[j].p_x2y;  if(s_x3 == px3[j].x3 && px3[j].y == class_y)s_px_3 = px3[j].p_x3y;  if(s_x4 == px4[j].x4 && px4[j].y == class_y)s_px_4 = px4[j].p_x4y;  if(s_x5 == px5[j].x5 && px5[j].y == class_y)s_px_5 = px5[j].p_x5y;  if(s_x6 == px6[j].x6 && px6[j].y == class_y)s_px_6 = px6[j].p_x6y;  }  s_px_7=px7[i].p_x7y;s_px_8=px8[i].p_x8y;result[i] = p[i] * s_px_1 * s_px_2*s_px_3* s_px_4* s_px_5* s_px_6*s_px_7*s_px_8;  //p[0]代表好瓜所占的比例  p[1]代表坏瓜所占的比例class_y--;  }  cout << "###########################<分类结果>###########################"<<endl; cout << endl << "all results:";  cout <<"可能为好瓜的概率"<< result[0] << "   " <<"可能为坏瓜的概率"<< result[1] << endl<<endl;  //0代表否(不是好瓜),1代表是好瓜,其中result[0]存放好瓜可能概率result[1]坏瓜所占比例cout << "###########################<预测结果>###########################"<<endl<<endl;  i =0;if(result[i] < result[i+1])  //如果坏瓜概率>好瓜概率{  class_y = 0; cout << "属性为:("<< s_x1 << "," << s_x2 << "," << s_x3 << "," << s_x4 << "," << s_x5 << "," << s_x6<< "," << s_x7<< "," << s_x8 << ")所属的类是:" << class_y<< "-----------坏瓜"<<endl<<endl;  }  else                        //好瓜概率>坏瓜概率{class_y=1;cout << "属性为:("<< s_x1 << "," << s_x2 << "," << s_x3 << "," << s_x4 << "," << s_x5 << "," << s_x6 << "," << s_x7<< "," << s_x8 << ")所属的类是:" << class_y  <<"-----------好瓜"<< endl<<endl;  }/*cout << "("<< s_x1 << "," << s_x2 << ")所属的类是:" << class_y + 1 << endl;  */system("pause");return 0;  
}  

“`

分类结果

这里写图片描述

UML 图:

这里写图片描述

源码下载地址

http://download.csdn.net/detail/u011557212/9700532

这篇关于C++ 朴素贝叶斯模型(Naive Bayesian Model,NBM)实现, 西瓜实验数据集 基于周志华老师机器学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/411076

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;