程序猿成长之路之数据挖掘篇——距离公式介绍

上一篇介绍了朴素贝叶斯,那么这次讲讲距离公式

什么是距离公式

用自己的话来说距离公式就是判断两个属性(参数)相似度的度量公式,比如以两点间距离为例,A地经纬度为(110.9802,120.9932),B地经纬度为(110.9980,120.8280), C地经纬度为(98.0232,110.9829),那么我们可以得出|AB| < |AC|,也就是说A地离B地的距离更近。再举个例子,同一个学校里有不同的学生,学生又有性别、年龄、兴趣爱好等属性,那么如果两个学生之间的性别、年龄、兴趣爱好等属性越接近,那么这两个学生的距离公式所得出的结果也就越小,两个学生也就越相像。

为什么要有距离公式

距离公式存在的意义在于不仅可以计算两个数值属性的相似度(如同上述的经纬度信息),而且可以计算两个度量甚至标称属性的相似度。
* 数值、度量、标称、二元属性的定义详见: 数据挖掘介绍https://blog.csdn.net/qq_31236027/article/details/137046475
而计算相似度的意义在于之后可以区分不同对象的差异性,从而方便后续的挖掘关联规则并进行相似度推荐。

常见的距离计算方式(后续会拓展展开讲讲)

数值属性的距离计算公式:

  1. 欧几里得距离公式
  2. 曼哈顿距离公式
  3. 上确界距离(切比雪夫距离)公式
  4. 闵可夫斯基距离公式

序数属性的距离计算方式:
若设置Rif 表示第i个对象的第f个属性的值,且该属性为序数属性,该属性有n个可选的值,且每个值的权重相同,又设置Zif为序数距离计算后的值,则有:
Zif = (Rif - 1) / n

标称属性的距离计算公式:
d(i,j) = (p-m) / p ⇒ 个人理解为不同的属性占全部属性的比例。

二元属性的距离计算公式:

  1. Jaccard公式:sim(i,j) = q / q + r + s, d(i,j) = 1 - sim(i,j)
  2. 余弦相似度公式

混合属性的距离计算公式:
sim(i,j) = Σ(f=1, p) δij(f) * sim(i,j) (f) / Σ(f=1,p) δij(f)
怎么理解呢?后续会详细展开讲讲

欧几里得距离公式

假设有A地和B地,经纬度分别为(x1,y1)和(x2,y2)
那么AB间的距离d(A,B) = |AB| = (√该符号表示根号) √(x1-x2)^2 + (y1-y2)^2
也就是取不同数值属性的差的平方和再进行开根运算。得出的结果就是欧几里得距离公式得出的结果

曼哈顿距离公式

假设有A地和B地,经纬度分别为(x1,y1)和(x2,y2)
那么AB间的距离d(A,B) = |AB| = |x1-x2| + |y1 -y2|
也就是取不同数值属性的差的绝对值和。得出的结果就是曼哈顿距离得出的结果

闵可夫斯基距离公式

假设有A地和B地,经纬度分别为(x1,y1)和(x2,y2)
那么AB间的距离d(A,B) = √(h) |x1- x2|^h + |y1-y2|^h = (Σ(f=1,2) |xAf- xBf| ^h)^1/h
也就是取不同数值属性的差的h次方求和再进行开h次方根运算。得出的结果就是闵可
夫斯基距离公式得出的结果

上确界距离(切比雪夫距离)公式

假设有A地和B地,经纬度分别为(x1,y1)和(x2,y2)
那么AB间的距离d(A,B) = limh->∞((Σ(f=1,2) |xAf- xBf| ^h)^1/h = max(f=1, p) |xAf- XBf|
也就是取闵可夫斯基距离公式的极限,约等于差异最大的属性的差值。
上确界距离公式推导可见:https://blog.csdn.net/qq_31236027/article/details/106763491

序数属性的距离计算

例如:现在有一个属性叫成绩,其中有3个值,分别为好,一般,差,那么该属性可以进行序数化,也就是用数字代替文本求距离。(假设权重一致)
P(好) = (3-1)/(3-1) = 1, #前一个(3-1) 表示的是值的位置,后一个(3-1)是为了将值映射到[0.0,1.0]上
P(一般) = (2-1)/(3-1) = 0.5
P(差) = (1-1) / (3-1) = 0
之后计算距离就方便了,可以利用数值属性的距离计算公式进行计算。

标称属性的距离计算

标称属性计算就很简单,求出不相同的属性的数量去除以对象A和B之间所有标称属性
数量就是标称属性的距离。

二元属性的距离计算

Jaccard距离计算公式:
假设对象i属性值为1且对象j属性值也为1的二元属性数量为q,对象i属性值为0但对象j属性值为1的二元属性数量为s,对象i属性值为1但是对象j属性值为0的二元属性数量为r,对象i和对象j属性值均为0的属性数量为t,那么有:
在这里插入图片描述
sim(i,j) = q(对象i和对象j属性的值都为1) + t 对象i和对象j属性的值都为0) / (q+r+s+t)
又有:对象i和对象j属性值均为0的属性没有意义,所以上述公式可以优化成以下公式:
sim(i,j) = q / q + r + s = 1- d(i,j) #该公式为jaccard公式。

余弦相似度公式:
sim(i,j) = |A ∩ B| / |A ∪ B|

混合属性的距离计算

sim(i,j) = Σ(f=1, p) δij(f) * sim(i,j) (f) / Σ(f=1,p) δij(f)
就是可以简单理解为标称、序数、数值、二元属性的距离计算完成后进行求和之后取平均值,

相关代码

各位小伙伴可以借鉴以下,以下是距离公式的java实现

package diffUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 距离公式
 * @author zygswo
 *
 */
public class DiffUtils {
	
	/**
	 * 测试对象
	 * @author zygswo
	 *
	 */
	class TestObject {
		@Override
		public String toString() {
			return "TestObject [name=" + name + ", age=" + age + ", gender=" + gender + ", myHobby=" + myHobby
					+ ", myDream=" + myDream + "]";
		}
		public List<MyHobby> getMyHobby() {
			return myHobby;
		}
		public TestObject setMyHobby(List<MyHobby> myHobby) {
			this.myHobby = myHobby;
			return this;
		}
		public String getName() {
			return name;
		}
		public TestObject setName(String name) {
			this.name = name;
			return this;
		}
		public int getAge() {
			return age;
		}
		public TestObject setAge(int age) {
			this.age = age;
			return this;
		}
		public String getGender() {
			return gender;
		}
		public TestObject setGender(String gender) {
			this.gender = gender;
			return this;
		}
		String name;
		
		@Elem(weight=0.1,type = ElemType.NUMBER)
		int age;
		
		@Elem(weight=0.2,type = ElemType.XUSHU,list={"男","女"})
		String gender;
		
		@Elem(weight=0.3)
		List<MyHobby> myHobby;
		
		@Elem(weight=0.4)
		List<String> myDream;
		
		public TestObject(String name, int age, String gender) {
			super();
			this.name = name;
			this.age = age;
			this.gender = gender;
		}
		
		public TestObject(String name, int age, String gender,List<MyHobby> myHobby) {
			this(name,age,gender);
			this.myHobby = myHobby;
		}
		
		public TestObject(String name, int age, String gender,List<MyHobby> myHobby, List<String> myDreams) {
			this(name,age,gender);
			this.myHobby = myHobby;
			this.myDream = myDreams;
		}
		
		
	}
	
	/**
	 * 欧几里得距离公式
	 * @param obj1
	 * @param obj2
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public static <T> double EuclidDistance(T obj1, T obj2) 
			throws IllegalArgumentException, IllegalAccessException {
		Class<?> cls = obj1.getClass();
		Field[] fs = cls.getDeclaredFields();
		double result = 0.0;
		for (Field f:fs) {
			f.setAccessible(true);
			Object xVal = f.get(obj1);
			Object yVal = f.get(obj2);
			long x = xVal.hashCode();
			long y = yVal.hashCode();
			System.out.println("x = " + x);
			System.out.println("y = " + y);
			result += EuclidDistance(x,y,1.0);
			System.out.println("result = " + result);
		}
		return Math.sqrt(result);
	}
	
	/**
	 * 计算相似度
	 * @param obj1
	 * @param obj2
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public static <T> T calculDiff(T obj1, T ... obj2) 
			throws IllegalArgumentException, IllegalAccessException {
		double min = 1.0;
		T mostLikelyItem = null;
		for (T obj : obj2) {
			double res = Double.parseDouble(calculDiff(obj1, obj));
			System.out.println("res = " + res);
			if (res < min) {
				min = res;
				mostLikelyItem = obj;
			}
		}
		return mostLikelyItem;
	}
	
	/**
	 * 计算相似度
	 * @param obj1
	 * @param obj2
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	@SuppressWarnings("rawtypes")
	public static <T> String calculDiff(T obj1, T obj2) 
			throws IllegalArgumentException, IllegalAccessException {
		Class<?> cls = obj1.getClass();
		Class<?> cls2 = obj2.getClass();
		if (!cls.getName().equalsIgnoreCase(cls2.getName())) {
			throw new IllegalArgumentException("参数类型不匹配");
		}
		Field[] fs = cls.getDeclaredFields();
		double result = 0.0, restWeight = 1.0; //result=相似度,restWeight=剩余权重
		int blankWeightFieldCount = 0; //elem中权重为空的field数量
		//计算变量数量
		for (Field f0:fs) {
			Elem elem0 = f0.getAnnotation(Elem.class);
			if (elem0 != null) {
				if (elem0.weight() == 1) {
					blankWeightFieldCount++;
				} else {
					restWeight = restWeight - elem0.weight();
					restWeight = Double.parseDouble(
							String.format("%.2f",restWeight)
					);
				}
				if (restWeight < 0) {
					throw new IllegalArgumentException("权重总量分配超过1");
				}
			}
		}
		for (Field f:fs) {
			f.setAccessible(true);
			Object xVal = f.get(obj1);
			Object yVal = f.get(obj2);
			Elem elem = f.getAnnotation(Elem.class);
			if (elem == null) {
				continue;
			}
			if (xVal instanceof ArrayList && yVal instanceof ArrayList) {
				Object[] objList1 = ((ArrayList)xVal).toArray();
				Object[] objList2 = ((ArrayList)yVal).toArray();
				Object[] objList3 = new Object[objList1.length + objList2.length];
				/**
				 * 1. 数组复制
				 * 2. 数组排序
				 * 3. 利用jaccard公式计算相似度(相异性 为 1- 相似度)
				 */
				//数组进行复制
				System.arraycopy(objList1, 0, objList3, 0, objList1.length);
				System.arraycopy(objList2, 0, objList3, objList1.length, objList2.length);
				//数组排序
				Arrays.sort(objList3);
				int same = 0,total = objList3.length;
				for (int i = 0; i < objList3.length-1;i++) {
					Object pre = objList3[i];
					Object after = objList3[i+1];
					if (pre.equals(after)) {
						same++;		//重复的元素++
						total--;	//两个重复了,减去一个
						i++;
					}
				}
				//简单规则,jaccard公式计算相似度(相异性 为 1- 相似度)
				System.out.println("same = "  + same);
				System.out.println("total = "  + total);
				if (total != 0) {
					result += elem.weight() * (1 - same / (total * 1.0));
					System.out.println("result = " + result);
				}
			} else {
				double temp = calcDiff(f,xVal,yVal);
				System.out.println("temp = " + temp);
				/**
				 * 如果field权重为1,那么相似度 = temp /权重为1的所有field数量
				 * 否则就按照权重进行分配。
				 * 例如:
				 */
				if (elem.weight() > 0 && elem.weight() < 1) {
					temp = temp * elem.weight();
				} else {
					temp = temp * restWeight / blankWeightFieldCount;
				}
//				System.out.println("temp = " + temp);
				result += temp;
				System.out.println("result = " + result);
			}
		}
		return String.format("%.2f",result);
	}
	
	private static double calcDiff(Field f,Object xVal, Object yVal) {
		long x = xVal.hashCode();
		long y = yVal.hashCode();
		System.out.println("x = " + x);
		System.out.println("y = " + y);
		Elem elem = f.getAnnotation(Elem.class);
		List<String> elemVals = Arrays.asList(elem.list());
		double temp = 0.0;
		switch(elem.type()) {
			case NUMBER:
				if (x == y) {
					temp =  0;
				} else {
					double max = x > y ? x : y;
					temp = Math.sqrt(EuclidDistance(x,y,1.0))/(max * 1.0);
					temp = Double.parseDouble(String.format("%.2f", temp));
				}
				break;
			case ERYUAN: temp = (x == y) ? 0 : 1; break;
			case BASIC: temp = (x == y) ? 0 : 1;break;
			case XUSHU:
				int xIndex = elemVals.indexOf(xVal);
				int yIndex = elemVals.indexOf(yVal);
				System.out.println("xIndex = " + xIndex);
				System.out.println("yIndex = " + yIndex);
				if (xIndex == -1) {
					throw new IllegalArgumentException("第一个对象的序数参数" + f.getName() + "值不匹配");	
				}
				if (yIndex == -1) {
					throw new IllegalArgumentException("第二个对象的序数参数" + f.getName() + " 值不匹配");	
				}
				temp = Math.abs(xIndex - yIndex)/(elemVals.size() * 1.0); break;
			default:
				break; 
		}
		return temp;
	}

	/**
	 * 欧几里得距离公式
	 * @param x0
	 * @param x1
	 */
	private static double EuclidDistance(long x0, long x1,double weight){
		return Math.pow(Math.abs(x0-x1), 2) * weight;
	}
	
	/**
	 * 数据统计
	 */
	private static <T extends TestObject> List<MyStatistics> getMyStatistics(T... objList){
		Map<String, List<MyHobby>> hobbyMap = new ConcurrentHashMap<>();
		Map<String, Integer> countMap = new ConcurrentHashMap<>();
		List<MyStatistics> myStatistics = new ArrayList<>();
		for (T obj: objList) {
			String gender = obj.getGender();
			countMap.put(gender,countMap.get(gender)== null ? 1 : countMap.get(gender) + 1);
			if (hobbyMap.get(gender) == null) {
				List<MyHobby> myHobbyList = obj.getMyHobby();
				hobbyMap.put(gender,myHobbyList);
				System.out.println(gender);
				System.out.println(myHobbyList.toString());
			} else {
				List<MyHobby> mapList = hobbyMap.get(gender);
				List<MyHobby> myHobbyList = obj.getMyHobby();
				for (MyHobby myHobby: myHobbyList) {
					if (!mapList.contains(myHobby)) {
						mapList.add(myHobby);
					}
				}
				hobbyMap.put(gender,mapList);
			}
		}
		for (String gender: hobbyMap.keySet()) {	
			myStatistics.add(new MyStatistics().setGender(gender)
					.setMyHobbyList(hobbyMap.get(gender)).setNbPerson(countMap.get(gender)));
		}
 		return myStatistics;
	}

	
	public static void main(String[] args) {
		DiffUtils util = new DiffUtils();
		MyHobby h1 = new MyHobby("爬山");
		MyHobby h2 = new MyHobby("音乐");
		MyHobby h3 = new MyHobby("看书");
		MyHobby h4 = new MyHobby("追剧");
		MyHobby h5 = new MyHobby("摄影");
		MyHobby h6 = new MyHobby("户外运动");
		List<MyHobby> list1 = new ArrayList<>();
		list1.add(h1);
		list1.add(h2);
		list1.add(h3);
		list1.add(h4);
		list1.add(h5);
		List<MyHobby> list2 = new ArrayList<>();
		list2.add(h1);
		list2.add(h2);
		list2.add(h3);
		list2.add(h4);
		List<MyHobby> list3 = new ArrayList<>();
		list3.add(h6);
		list3.add(h2);
		List<String> characterList1 = new ArrayList<>();
		characterList1.add("坚强");
		characterList1.add("自信");
		characterList1.add("乐观");
		List<String> characterList2 = new ArrayList<>();
		characterList2.add("坚强");
		characterList2.add("自信");
		characterList2.add("乐观");
		TestObject obj1 = util.new TestObject("zyg",18,"男",list1,characterList1);
		TestObject obj2 = util.new TestObject("zcx",15,"女",list2,characterList2);
		TestObject obj3 = util.new TestObject("zyg",22,"男",list3,characterList1);
		System.out.println(getMyStatistics(obj1,obj2,obj3));
		try {
			double res = Double.parseDouble(calculDiff(obj1,obj2));
			System.out.println("相似度:" + (1-res));
			System.out.println(calculDiff(obj1,obj2,obj3));
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

—————————————— 有问题的话评论区见——————————————

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

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

相关文章

Java | Leetcode Java题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode partition(ListNode head, int x) {ListNode small new ListNode(0);ListNode smallHead small;ListNode large new ListNode(0);ListNode largeHead large;while (head ! null) {if (head.val < x…

PyQt5中的LineEdit单行文本框

文章目录 1. 简介1.1 常用方法&#xff1a;1.2 常用信号&#xff1a; 2. LineEdit常用方法使用案例3. LineEdit常用信号使用案例 1. 简介 在PyQt5中&#xff0c;LineEdit&#xff08;单行文本框&#xff09;是一个常用的组件&#xff0c;它允许用户输入文本。以下是一些LineEd…

【游戏引擎】unity

目录 Unity入门教程&#xff1a;从零到英雄的旅程前言第一步&#xff1a;下载和安装Unity第二步&#xff1a;创建你的第一个Unity项目第三步&#xff1a;熟悉Unity界面第四步&#xff1a;创建一个简单的游戏对象第五步&#xff1a;编写脚本赋予游戏对象生命第六步&#xff1a;运…

华为OD机试【统一限载货物数最小值】(java)(200分)

1、题目描述 火车站附近的货物中转站负责将到站货物运往仓库&#xff0c;小明在中转站负责调度 2K 辆中转车(K辆干货中转车&#xff0c;K 辆湿货中转车)货物由不同供货商从各地发来&#xff0c;各地的货物是依次进站&#xff0c;然后小明按照卸货顺序依次装货到中转车&#xf…

如何解决pycharm在HTML文件中注释快捷键出错的问题(HTML注释规则出错)

文章目录 💢 问题 💢🏡 演示环境 🏡💯 解决方案 💯⚓️ 相关链接 ⚓️💢 问题 💢 你是否在编程时遇到过这样的烦恼?当你正专注地编写HTML代码,想要快速注释掉某部分内容时,却发现PyCharm的注释快捷键失灵了(没有使用正确的注释格式)。这不仅打断了你的工作…

【论文笔记】利用扩散模型DDPM做变化检测change detection

去噪扩散模型DDPM去年开始在各种视觉任务取得惊人的效果&#xff0c;变化检测领域也不例外&#xff0c;本文介绍两篇关于如何使用扩散模型实现变化检测的论文。第一篇做法较为自然&#xff0c;先利用遥感数据预训练DDPM&#xff0c;然后将预训练好的网络当作变化检测任务的特征…

设计模式-结构型-适配器模式-Adapter

地址类 public class Address {public void street() {System.out.println("普通的街道");}public void zip() {System.out.println("普通的邮政编码");}public void city() {System.out.println("普通的城市");} } 荷兰地址类 public class …

用lobehub打造一个永久免费的AI个人助理

Lobe Chat是一个开源的高性能聊天机器人框架&#xff0c;它被设计来帮助用户轻松创建和部署自己的聊天机器人。这个框架支持多种智能功能&#xff0c;比如语音合成&#xff08;就是让机器人能说话&#xff09;&#xff0c;还能理解和处理多种类型的信息&#xff0c;不仅限于文字…

关于USB 3.1电气参数的探讨

目录 0 引言 1 抖动预算 2 时钟恢复-CDR 3 测试码型-PRBS16 4 传输码型-128b/132b 5 眼图模板-Eye Mask 6 发射均衡 7 接收均衡 7.1 CTLE均衡 7.2 DFE均衡

Postman历史版本安装与runner测试

前言 实际上就是笔者本地做demo&#xff0c;postman使用了最新版本&#xff0c;本身也没问题&#xff0c;不过postman不支持不登录做runner测试了&#xff0c;很多功能必须登录账号才能使用&#xff0c;否则只能使用http工具发送的能力&#xff0c;而postman本身就是一个简单工…

栈和队列经典练习题

目录 前言&#xff1a; 一、括号匹配问题 1.题目描述 2.解题思路 3.题目链接 二、用队列实现栈 1.题目描述 2.解题思路 3.题目链接 三、用栈实现队列 1.题目描述 2.题目分析 3.题目链接 四、设计循环队列 1.题目描述 2. 题目分析 3.题目链接 最后 前言&#xff1a; 前…

JCR一区 | Matlab实现1D-2D-GASF-CNN-BiLSTM-MATT的多通道输入数据分类预测

JCR一区 | Matlab实现1D-2D-GASF-CNN-BiLSTM-MATT的多通道输入数据分类预测 目录 JCR一区 | Matlab实现1D-2D-GASF-CNN-BiLSTM-MATT的多通道输入数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 Matlab实现1D-2D-GASF-CNN-BiLSTM-MATT的多通道输入数据分类预…

未授权访问:VNC未授权访问

目录 1、漏洞原理 2、环境搭建 3、未授权访问 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好的文章&#xff1a; 这里附上大…

修改MTU值解决Linux下运行top命令卡死问题

上周明月的Linux服务器上运行top命令总是莫名的出现卡死现象&#xff0c;甚至是CtrlC都无法终止进程&#xff0c;今天终于抽空找到了解决办法&#xff0c;原来是需要修改Linux的MTU值&#xff0c;将服务器操作系统数据包调小&#xff0c;加上VxLAN数据包小于1500即可。 top命令…

Python-VBA函数之旅-sum函数

目录 一、sum函数的常见应用场景 二、sum函数使用注意事项 三、如何用好sum函数&#xff1f; 1、sum函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、sum函数的常…

摩苏尔大坝形变监测

摩苏尔大坝&#xff0c;是伊拉克最大的大坝。它位于底格里斯河35公里&#xff0c;北距摩苏尔市&#xff0c;这是一座粘土质地的水坝&#xff0c;高113米&#xff0c;长3.2公里&#xff0c;于1986落成。 大坝建成后不久&#xff0c;大坝就遇到了由软石膏地基造成的一些结构性问题…

jenkins连接ubuntu普通用户节点

1.创建credentials 2.创建node 3.在jenkins服务器还需要进行的操作&#xff08;jenkins服务器中&#xff09; mkdir /var/lib/jenkins/.ssh ssh-keyscan -H 192.168.110.204 >> /var/lib/jenkins/.ssh/known_hosts chown -R jenkins:jenkins /var/lib/jenkins/.ssh/ 4.…

试衣不再有界:Tunnel Try-on开启视频试衣应用新纪元

论文&#xff1a;https://arxiv.org/pdf/2404.17571 主页&#xff1a;https://mengtingchen.github.io/tunnel-try-on-page/ 一、摘要总结 随着虚拟试衣技术的发展&#xff0c;消费者和时尚行业对于能够在视频中实现高质量虚拟试衣的需求日益增长。这项技术允许用户在不实际穿…

【实战】算法思路总结

面试过程中&#xff0c;总是被拷打&#xff0c;信心都要没了。但是也慢慢摸索出一些思路&#xff0c;希望对大家有帮助。 &#xff08;需要多用一下ACM模式&#xff0c;力扣模式提供好了模板&#xff0c;自己在IDEA里面写的话&#xff0c;还是会有些陌生&#xff09; 0、基本…

MFC重要的初始化函数InitInstance

MFC应用程序最早处理的类的初始化函数通常是CWinApp类的构造函数。CWinApp类是MFC应用程序的主类&#xff0c;负责整个应用程序的初始化和管理。 在MFC应用程序中&#xff0c;通常会创建一个派生自CWinApp类的应用程序类&#xff0c;例如CMyApp。在应用程序启动时&#xff0c;…