数据结构:线索二叉树

news2024/9/29 3:21:29

线索二叉树

通过前面对二叉树的学习,了解到二叉树本身是一种非线性结构,采用任何一种遍历二叉树的方法,都可以得到树中所有结点的一个线性序列。在这个序列中,除第一个结点外,每个结点都有自己的直接前趋;除最后一个结点外,每个结点都有一个直接后继。

在这里插入图片描述

例如,上图采用先序遍历的方法得到的结点序列为:1 2 4 5 3 6 7,在这个序列中,结点 2 的直接前趋结点为 1,直接后继结点为 4

什么是线索二叉树

如果算法中多次涉及到对二叉树的遍历,普通的二叉树就需要使用栈结构做重复性的操作。

线索二叉树不需要如此,在遍历的同时,使用二叉树中空闲的内存空间记录某些结点的前趋和后继元素的位置(不是全部)。这样在算法后期需要遍历二叉树时,就可以利用保存的结点信息,提高了遍历的效率。使用这种方法构建的二叉树,即为“线索二叉树”。

线索二叉树的结点结构

如果在二叉树中想保存每个结点前趋和后继所在的位置信息,最直接的想法就是改变结点的结构,即添加两个指针域,分别指向该结点的前趋和后继。

但是这种方式会降低树存储结构的存储密度。而对于二叉树来讲,其本身还有很多未利用的空间。

存储密度指的是数据本身所占的存储空间和整个结点结构所占的存储量之比。

每一棵二叉树上,很多结点都含有未使用的指向NULL的指针域。除了度为2的结点,度为 1 的结点,有一个空的指针域;叶子结点两个指针域都为NULL

规律:在有 n 个结点的二叉链表中必定存在 n+1 个空指针域。

线索二叉树实际上就是使用这些空指针域来存储结点之间前趋和后继关系的一种特殊的二叉树。

线索二叉树中,如果结点有左子树,则 lchild 指针域指向左孩子,否则 lchild 指针域指向该结点的直接前趋;同样,如果结点有右子树,则 rchild 指针域指向右孩子,否则 rchild 指针域指向该结点的直接后继。

为了避免指针域指向的结点的意义混淆,需要改变结点本身的结构,增加两个标志域,如下图2所示。线索二叉树中的结点结构

图2

在这里插入图片描述

LTagRTag 为标志域。实际上就是两个布尔类型的变量:

  • LTag 值为 0 时,表示 lchild 指针域指向的是该结点的左孩子;为 1 时,表示指向的是该结点的直接前趋结点;
  • RTag 值为 0 时,表示 rchild 指针域指向的是该结点的右孩子;为 1 时,表示指向的是该结点的直接后继结点。

结点结构代码实现:

#define TElemType int//宏定义,结点中数据域的类型
//枚举,Link为0,Thread为1
typedef enum PointerTag{
    Link,
    Thread
}PointerTag;
//结点结构构造
typedef struct BiThrNode{
    TElemType data;//数据域struct BiThrNode* lchild,*rchild;//左孩子,右孩子指针域
    PointerTag Ltag,Rtag;//标志域,枚举类型
}BiThrNode,*BiThrTree;

表示二叉树时,使用上图所示的结点结构构成的二叉链表,被称为线索链表;构建的二叉树称为线索二叉树

线索链表中的“线索”,指的是链表中指向结点前趋和后继的指针。二叉树经过某种遍历方法转化为线索二叉树的过程称为线索化。

对二叉树进行线索化

将二叉树转化为线索二叉树,实质上是在遍历二叉树的过程中,将二叉链表中的空指针改为指向直接前趋或者直接后继的线索。

线索化的过程即为在遍历的过程中修改空指针的过程。

在遍历过程中,如果当前结点没有左孩子,需要将该结点的 lchild 指针指向遍历过程中的前一个结点,所以在遍历过程中,设置一个指针(名为 pre ),时刻指向当前访问结点的前一个结点。代码实现(拿中序遍历为例):

//中序对二叉树进行线索化
void InThreading(BiThrTree p){
//如果当前结点存在
if (p) {
        InThreading(p->lchild);//递归当前结点的左子树,进行线索化//如果当前结点没有左孩子,左标志位设为1,左指针域指向上一结点 pre
if (!p->lchild) {
            p->Ltag=Thread;
            p->lchild=pre;
        }
//如果 pre 没有右孩子,右标志位设为 1,右指针域指向当前结点。
if (!pre->rchild) {
            pre->Rtag=Thread;
            pre->rchild=p;
        }
        pre=p;//线索化完左子树后,让pre指针指向当前结点
        InThreading(p->rchild);//递归右子树进行线索化
    }
}

注意:中序对二叉树进行线索化的过程中,在两个递归函数中间的运行程序,和之前介绍的中序遍历二叉树的输出函数的作用是相同的。

将中间函数移动到两个递归函数之前,就变成了前序对二叉树进行线索化的过程;后序线索化同样如此。

线索二叉树遍历

3 中是一个按照中序遍历建立的线索二叉树。其中,实线表示指针,指向的是左孩子或者右孩子。虚线表示线索,指向的是该结点的直接前趋或者直接后继。

在这里插入图片描述

图 3 线索二叉树

使用线索二叉树时,会经常遇到一个问题,如图 3 中,结点 b b b的直接后继直接通过指针域获得,为结点 ∗ * ;而由于结点 ∗ * 的度为2 ,无法利用指针域指向后继结点,整个链表断掉了。当在遍历过程,遇到这种问题是解决的办法就是:寻找先序、中序、后序遍历的规律,找到下一个结点。

在先序遍历过程中,如果结点因为有右孩子导致无法找到其后继结点,如果结点有左孩子,则后继结点是其左孩子;否则,就一定是右孩子。拿图 3 举例,结点 + 的后继结点是其左孩子结点 a ,如果结点 a 不存在的话,就是结点 *

在中序遍历过程中,结点的后继是遍历其右子树时访问的第一个结点,也就是右子树中位于最左下的结点。例如图 3 中结点 * ,后继结点为结点 c ,是其右子树中位于最左边的结点。反之,结点的前趋是左子树最后访问的那个结点。

后序遍历中找后继结点需要分为 3 种情况:

  1. 如果该结点是二叉树的根,后继结点为空;
  2. 如果该结点是父结点的右孩子(或者是左孩子,但是父结点没有右孩子),后继结点是父结点;
  3. 如果该结点是父结点的左孩子,且父结点有右子树,后继结点为父结点的右子树在后序遍历列出的第一个结点。

使用后序遍历建立的线索二叉树,在真正使用过程中遇到链表的断点时,需要访问父结点,所以在初步建立二叉树时,宜采用三叉链表做存储结构。

遍历线索二叉树非递归代码实现:

//中序遍历线索二叉树
void InOrderThraverse_Thr(BiThrTree p)
{
    while(p)
    {
//一直找左孩子,最后一个为中序序列中排第一的
        while(p->Ltag == Link){
            p = p->lchild;
        }
        cout << p->data;//操作结点数据//当结点右标志位为1时,直接找到其后继结点
        while(p->Rtag == Thread && p->rchild !=NULL){
            p = p->rchild;
            cout <<  p->data;
        }
//否则,按照中序遍历的规律,找其右子树中最左下的结点,也就是继续循环遍历
        p = p->rchild;
    }
}

整节完整代码

#include "iostream"
using namespace std;
#define TElemType char//宏定义,结点中数据域的类型
//枚举,Link为0,Thread为1
typedef enum {
    Link,
    Thread
}PointerTag;
//结点结构构造
typedef struct BiThrNode {
    TElemType data;//数据域
    struct BiThrNode* lchild, *rchild;//左孩子,右孩子指针域
    PointerTag Ltag, Rtag;//标志域,枚举类型
}BiThrNode, *BiThrTree;

BiThrTree pre = NULL;

//采用前序初始化二叉树
//中序和后序只需改变赋值语句的位置即可
void CreateTree(BiThrTree * tree) {
    char data;
    cin >> data;
    if (data != '#') {
        if (!((*tree) = (BiThrNode*)malloc(sizeof(BiThrNode)))) {
            cout << "申请结点空间失败";
            return;
        }
        else {
            (*tree)->data = data;//采用前序遍历方式初始化二叉树
            (*tree)->Ltag = Link;
            (*tree)->Rtag = Link;
            CreateTree(&((*tree)->lchild));//初始化左子树
            CreateTree(&((*tree)->rchild));//初始化右子树
        }
    }
    else {
        *tree = NULL;
    }
}
//中序对二叉树进行线索化
void InThreading(BiThrTree p) {
    //如果当前结点存在
    if (p) {
        InThreading(p->lchild);//递归当前结点的左子树,进行线索化
        //如果当前结点没有左孩子,左标志位设为1,左指针域指向上一结点 pre
        if (!p->lchild) {
            p->Ltag = Thread;
            p->lchild = pre;
        }
        //如果 pre 没有右孩子,右标志位设为 1,右指针域指向当前结点。
        if (pre && !pre->rchild) {
            pre->Rtag = Thread;
            pre->rchild = p;
        }
        pre = p;//pre指向当前结点
        InThreading(p->rchild);//递归右子树进行线索化
    }
}
//中序遍历线索二叉树
void InOrderThraverse_Thr(BiThrTree p)
{
    while (p)
    {
        //一直找左孩子,最后一个为中序序列中排第一的
        while (p->Ltag == Link) {
            p = p->lchild;
        }
        cout << p->data;
        //当结点右标志位为1时,直接找到其后继结点
        while (p->Rtag == Thread && p->rchild != NULL)
        {
            p = p->rchild;
            cout << p->data;
        }
        //否则,按照中序遍历的规律,找其右子树中最左下的结点,也就是继续循环遍历
        p = p->rchild;
    }
}

int main() {
    BiThrTree t;
    cout << "输入前序二叉树:" << '\n';
    CreateTree(&t);
    InThreading(t);
    cout << "输出中序序列:" << '\n';
    InOrderThraverse_Thr(t);
    return 0;
}

运行结果

输入前序二叉树:
124###35##6##
输出中序序列:
4 2 1 5 3 6

通过前一节对线索二叉树的学习,其中,在遍历使用中序序列创建的线索二叉树时,对于其中的每个结点,即使没有线索的帮助下,也可以通过中序遍历的规律找到直接前趋和直接后继结点的位置。

也就是说,建立的线索二叉链表可以从两个方向对结点进行中序遍历。通过前一节的学习,线索二叉链表可以从第一个结点往后逐个遍历。但是起初由于没有记录中序序列中最后一个结点的位置,所以不能实现从最后一个结点往前逐个遍历。

双向线索链表的作用就是可以让线索二叉树从两个方向实现遍历。

双向线索二叉树的实现过程

在线索二叉树的基础上,额外添加一个结点。此结点的作用类似于链表中的头指针,数据域不起作用,只利用两个指针域(由于都是指针,标志域都为 0 )。

左指针域指向二叉树的树根,确保可以正方向对二叉树进行遍历;同时,右指针指向线索二叉树形成的线性序列中的最后一个结点。

这样,二叉树中的线索链表就变成了双向线索链表,既可以从第一个结点通过不断地找后继结点进行遍历,也可以从最后一个结点通过不断找前趋结点进行遍历。

在这里插入图片描述

图4 双向线索二叉链表

代码实现:

//建立双向线索链表
void InOrderThread_Head(BiThrTree *h, BiThrTree t)
{
//初始化头结点
    (*h) = (BiThrTree)malloc(sizeof(BiThrNode));
    if((*h) == NULL){
        cout << "申请内存失败";
        return ;
    }
    (*h)->rchild = *h;
    (*h)->Rtag = Link;
//如果树本身是空树
if(!t){
        (*h)->lchild = *h;
        (*h)->Ltag = Link;
    }
    else{
        pre = *h;//pre指向头结点
        (*h)->lchild = t;//头结点左孩子设为树根结点
        (*h)->Ltag = Link;
        InThreading(t);//线索化二叉树,pre结点作为全局变量,线索化结束后,pre结点指向中序序列中最后一个结点
        pre->rchild = *h;
        pre->Rtag = Thread;
        (*h)->rchild = pre;
    }
}

双向线索二叉树的遍历

双向线索二叉树遍历时,如果正向遍历,就从树的根结点开始。整个遍历过程结束的标志是:当从头结点出发,遍历回头结点时,表示遍历结束。

//中序正向遍历双向线索二叉树
void InOrderThraverse_Thr(BiThrTree h)
{
    BiThrTree p;
    p = h->lchild;//p指向根结点
while(p != h)
    {
        while(p->Ltag == Link)//当ltag = 0时循环到中序序列的第一个结点
        {
            p = p->lchild;
        }
				cout << p->data;//显示结点数据,可以更改为其他对结点的操作
while(p->Rtag == Thread && p->rchild != h)
        {
            p = p->rchild;
						cout << p->data;
        }

        p = p->rchild;//p进入其右子树
    }
}

逆向遍历线索二叉树的过程即从头结点的右指针指向的结点出发,逐个寻找直接前趋结点,结束标志同正向遍历一样:

//中序逆方向遍历线索二叉树
void InOrderThraverse_Thr(BiThrTree h){
    BiThrTree p;
    p=h->rchild;
    while (p!=h) {
        while (p->Rtag==Link) {
            p=p->rchild;
        }
        cout << p->data;
//如果lchild为线索,直接使用,输出
while (p->Ltag==Thread && p->lchild !=h) {
            p=p->lchild;
            cout << p->data;
        }
        p=p->lchild;
    }
}

完整代码实现

#include "iostream"
using namespace std;
#define TElemType char//宏定义,结点中数据域的类型
//枚举,Link为0,Thread为1
typedef enum {
    Link,
    Thread
}PointerTag;
//结点结构构造
typedef struct BiThrNode {
    TElemType data;//数据域
    struct BiThrNode* lchild, *rchild;//左孩子,右孩子指针域
    PointerTag Ltag, Rtag;//标志域,枚举类型
}BiThrNode, *BiThrTree;

BiThrTree pre = NULL;

//采用前序初始化二叉树
//中序和后序只需改变赋值语句的位置即可
void CreateTree(BiThrTree * tree) {
    char data;
    cin >> data;
    if (data != '#') {
        if (!((*tree) = (BiThrNode*)malloc(sizeof(BiThrNode)))) {
            cout << "申请结点空间失败";
            return;
        }
        else {
            (*tree)->data = data;//采用前序遍历方式初始化二叉树
            (*tree)->Ltag = Link;
            (*tree)->Rtag = Link;
            CreateTree(&((*tree)->lchild));//初始化左子树
            CreateTree(&((*tree)->rchild));//初始化右子树
        }
    }
    else {
        *tree = NULL;
    }
}
//中序对二叉树进行线索化
void InThreading(BiThrTree p) {
    //如果当前结点存在
    if (p) {
        InThreading(p->lchild);//递归当前结点的左子树,进行线索化
        //如果当前结点没有左孩子,左标志位设为1,左指针域指向上一结点 pre
        if (!p->lchild) {
            p->Ltag = Thread;
            p->lchild = pre;
        }
        //如果 pre 没有右孩子,右标志位设为 1,右指针域指向当前结点。
        if (pre && !pre->rchild) {
            pre->Rtag = Thread;
            pre->rchild = p;
        }
        pre = p;//pre指向当前结点
        InThreading(p->rchild);//递归右子树进行线索化
    }
}
//建立双向线索链表
void InOrderThread_Head(BiThrTree *h, BiThrTree t)
{
    //初始化头结点
    (*h) = (BiThrTree)malloc(sizeof(BiThrNode));
    if ((*h) == NULL) {
        cout << "申请内存失败";
        return;
    }
    (*h)->rchild = *h;
    (*h)->Rtag = Link;
    //如果树本身是空树
    if (!t) {
        (*h)->lchild = *h;
        (*h)->Ltag = Link;
    }
    else {
        pre = *h;//pre指向头结点
        (*h)->lchild = t;//头结点左孩子设为树根结点
        (*h)->Ltag = Link;
        InThreading(t);//线索化二叉树,pre结点作为全局变量,线索化结束后,pre结点指向中序序列中最后一个结点
        pre->rchild = *h;
        pre->Rtag = Thread;
        (*h)->rchild = pre;
    }
}
//中序正向遍历双向线索二叉树
void InOrderThraverse_Thr(BiThrTree h)
{
    BiThrTree p;
    p = h->lchild;           //p指向根结点
    while (p != h)
    {
        while (p->Ltag == Link)   //当ltag = 0时循环到中序序列的第一个结点
        {
            p = p->lchild;
        }
        cout << p->data;
        while (p->Rtag == Thread && p->rchild != h)
        {
            p = p->rchild;
            cout << p->data;
        }

        p = p->rchild;           //p进入其右子树
    }
}
int main() {
    BiThrTree t;
    BiThrTree h;
    cout << "输入前序二叉树:" << '\n';
    CreateTree(&t);
    InOrderThread_Head(&h, t);
    cout << "输出中序二叉树:" << '\n';
    InOrderThraverse_Thr(h);
    return 0;
}

运行结果:

输入前序二叉树:
124###35##6##
输出中序序列:
4 2 1 5 3 6

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

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

相关文章

MySql忘记密码如何修改

前言 好久没用数据库的软件了&#xff0c;要用的时候突然发现密码已经忘记了&#xff0c;怎么试都不对&#xff0c;心态直接爆炸&#xff0c;上一次用还是22年6月份&#xff0c;也记不得当时用数据库干什么了&#xff0c;这份爆炸浮躁的心态值得这样记录一下&#xff0c;警示自…

国内常见的16款低代码开发平台介绍

本文给大家讲解3种不同方向的低代码/无代码开发平台。 第一种&#xff1a;企业级低代码开发平台&#xff0c;企业级这一概念是指&#xff1a;能把企业方方面面的业务需求全都能覆盖到&#xff0c;&#xff08;包括很多定制化且高度复杂的核心应用系统&#xff0c;如ERP、MES、…

浅析嵌入式GUI框架-LVGL

LVGL是什么&#xff1f; LVGL (Light and Versatile Graphics Library) 是最流行的免费开源嵌入式图形库&#xff0c;可为任何 MCU、MPU 和显示类型创建漂亮的 UI。 嵌入式GUI框架对比 Features/框架LVGLFlutter-elinuxArkUI(鸿蒙OS)AWTKQTMIniGUIemWinuC/GUI柿饼UI跨平台…

神经数据库:用于使用 ChatGPT 构建专用 AI 代理的下一代上下文检索系统 — (第 2/3 部分)

书接上回理解构建LLM驱动的聊天机器人时的向量数据库检索的局限性 - &#xff08;第1/3部分&#xff09;_阿尔法旺旺的博客-CSDN博客 其中我们强调了&#xff08;1&#xff09;嵌入生成&#xff0c;然后&#xff08;2&#xff09;使用近似近邻&#xff08;ANN&#xff09;搜索…

Reinforcement Learning with Code 【Chapter 8. Value Funtion Approximation】

Reinforcement Learning with Code This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Reinforcement Learning, . 文章…

2.9 线性表的划分

划分规则: 以某个元素为标准, 把顺序表中的元素分为左右两个部分, 标准元素称为枢轴. 考研中划分有三种题型(划分策略). 题型一 要求: 给一个顺序表, 以第一个元素为枢轴, 将该顺序表划分为左右两部分, 使得左边的所有元素都小于枢轴, 右边的所有元素都大于枢轴. 并且枢轴要…

基于Java+SpringBoot+vue前后端分离大学生就业招聘系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【雕爷学编程】Arduino动手做(174)---Sensor Shield V5.0传感器扩展板

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

c++学习(位图)[22]

位图 位图&#xff08;Bitmap&#xff09;是一种数据结构&#xff0c;用于表示一个固定范围的布尔值&#xff08;通常是0或1&#xff09;。它使用一个二进制位来表示一个布尔值&#xff0c;其中每个位的值表示对应位置的元素是否存在或满足某种条件。 位图可以用于解决一些特…

下级平台级联安防视频汇聚融合EasyCVR平台,层级显示不正确是什么原因?

视频汇聚平台安防监控EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等…

粘包处理的方式

为什么出现粘包&#xff1a; 发送端在发送的时候由于 Nagel 算法的存在会将字节数较小的数据整合到一起发送&#xff0c;导致粘包&#xff1b;接收端不知道发送端数据的长度&#xff0c;导致接收时无法区分数据&#xff1b; 粘包处理的方式&#xff1a; 通过在数据前面加上报…

OpenLayers入门,OpenLayers如何加载GeoJson多边形、线段、点和区域范围等数据并叠加到OpenLayers矢量图层上

专栏目录: OpenLayers入门教程汇总目录 前言 前面两章已经讲了OpenLayers如何加载GeoJson数据到矢量图层和webgl图层上,前面两章也是可以支持多边形、线段、点和区域范围灯数据加载的,只是没有设置样式,所以只能看到点,本章就相当于完整版本,可以将所有图形都详细展示出…

使用Wps减小PDF文件的大小

第一步、打开左上角的文件 第二步、点击打印选项 第三步、点击打印按钮

大学的python课程一般叫什么,大学开设python课程吗

大家好&#xff0c;小编为大家解答大学的python课程一般叫什么的问题。很多人还不知道大学python课有没有听的必要&#xff0c;现在让我们一起来看看吧&#xff01; 1、华中农业大学python期末考试会考原题吗 华中农业大芦如学python期末考试不会考原题。华中农业搜侍大学pyth…

Leetcode-每日一题【剑指 Offer II 075. 数组相对排序】

题目 给定两个数组&#xff0c;arr1 和 arr2&#xff0c; arr2 中的元素各不相同 arr2 中的每个元素都出现在 arr1 中 对 arr1 中的元素进行排序&#xff0c;使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。 示例&…

都2023年了还不会Node.js爬虫?快学起来!

爬虫简介 什么是爬虫 爬虫&#xff08;Web Crawler&#xff09;是一种自动化程序&#xff0c;可以在互联网上自动抓取网页&#xff0c;并从中提取有用的信息。 爬虫可以模拟人类浏览器的行为&#xff0c;自动访问网站、解析网页、提取数据等。 通俗来说&#xff0c;爬虫就像…

财报解读:新鲜感褪去后,微软直面AI的骨感现实?

微软交出了一份远观尚可&#xff0c;但近看承压的“答卷”。 北京时间2023年7月26日&#xff0c;微软披露了2023财年第四财季及全年财报。受生产力和业务流程部门和智能云部门等业务带动&#xff0c;微软第四财季营收561.89亿美元&#xff0c;同比增长8%&#xff1b;净利润200…

Java-day02(关键字,变量,进制转换,数据类型转换,运算符)

关键字&#xff0c;变量&#xff0c;进制转换&#xff0c;数据类型转换&#xff0c;运算符 1.关键字&#xff0c;保留字与标识符 Java区分大小写 1.1 关键字 定义:有特殊含义&#xff0c;用作专用的字符串&#xff08;单词&#xff09; 特点&#xff1a;关键字所以字母都为…

小程序 获取用户头像、昵称、手机号的组件封装(最新版)

在父组件引入该组件 <!-- 授权信息 --><auth-mes showModal"{{showModal}}" idautnMes bind:onConfirm"onConfirm"></auth-mes> 子组件详细代码为: authMes.wxml <!-- components/authMes/authMes.wxml --> <van-popup show…

vs2013 32位 编译的 dll,重新用vs2022 64位编译,所遇问题记录

目录 一、vs2013 32 DLL 转 VS2022 64 DLL 所遇问题 1、 LNK2038: 检测到“_MSC_VER”的不匹配项: 值“1800”不匹配值“1900” 2、原先VS2013 现在 VS2022 导致的vsnprintf 重定义问题 3、 无法解析的外部符号 __vsnwprintf_s 4、无法解析的外部符号__imp__CertFreeC…