学习笔记---不容错过的顺序表的应⽤~~

news2024/11/16 21:53:28


目录​​​​​​​

1. 基于动态顺序表实现通讯录项⽬

1.1 通讯录📇功能要求

1.2 总体思路分析🧐

1.3 创建+初始化+销毁顺序表🌞

1.3.1 contact.h

1.3.2 Seqlist.h

1.3.3 contact.c

1.3.4 text.c

1.3.5 代码运行测试

1.3.6 二次代码测试

1.4 添加+删除联系人👻

1.4.1 contatc.h

1.4.2 contact.c

1.4.3 tets.c

1.4.4 代码运行测试

1.5 修改联系人🙉

1.5.1 contatc.h

1.5.2 contact.c

1.5.3 tets.c

1.5.4 代码运行测试

1.5.5 contact.h优化🍎

1.5.6 test.c修改

1.5.7 二次代码运行测试

1.6 查看通讯录🥑

1.6.1 contatc.h

1.6.2 contact.c

1.6.3 tets.c

1.6.4 代码运行测试

1.7 查找指定联系人👤

1.7.1 contatc.h

1.7.2 contact.c

1.7.3 tets.c

1.7.4 代码运行测试

1.8 美观---菜单界面🏵️

1.8.1 test.c

1.9 通讯录📇代码运行测试

2. 顺序表经典算法

2.1 经典算法OJ题1: 移除元素🚨

2.1.1 题目

2.1.2 思路分析

2.1.3 代码实现

2.1.3.1 解法1

2.1.3.2 解法2

2.2 经典算法OJ题2: 合并两个有序数组☎️

2.2.2 思路分析

2.2.3 代码实现

3. 顺序表的问题及思考


1. 基于动态顺序表实现通讯录项⽬

1.1 通讯录📇功能要求

首先,我们看看通讯录需要实现什么功能:

1)⾄少能够存储100个⼈的通讯信息

2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等

3)增加联系⼈信息

4)删除指定联系⼈

5)查找制定联系⼈

6)修改指定联系⼈

7)显⽰联系⼈信息


1.2 总体思路分析🧐

首先,我们要使用上一期学习的动态顺序表实现通讯录📇,如果有不知道的小伙伴,可以移步到小江的上一篇博客:学习笔记---超基础+详细+新手的顺序表~~-CSDN博客动态顺序表的简单实现https://blog.csdn.net/2301_79184587/article/details/133842555 我们知道顺序表可以存储数据,但是通讯录存储比较多,所以我们把一个联系人的所有信息作为一个整体存储到顺序表,再进行对应接口的编写:

实现顺序表的创建,初始化,一系列具体操作,销毁

一系列具体操作:

头部/尾部增加联系⼈信息、头部/尾部删除指定联系⼈、查找制定联系⼈、指定位置修改联系⼈信息、显⽰联系⼈信息

注意⚠️

我们是在顺序表的基础上实现通讯录📇,所以我们直接在上一篇的动态顺序表的基础上实现📇



1.3 创建+初始化+销毁顺序表🌞

1.3.1 contact.h

//创建保存联系人数据的结构体
//定义联系人数据字节大小
#define NAME_MAX 100
#define SEX_MAX 10
#define PHONE_MAX 15
#define ADDR_MAX 100

typedef struct ContactInfo
{
	//采用定长数组
	char name[NAME_MAX];
	char sex[SEX_MAX] ;
	int age;
	char phone[PHONE_MAX] ;
	char addr[ADDR_MAX] ;
}CInfo;//重命名之后更加简洁方便

//通讯录的初始化和销毁
void ContactInit(contact* con);
void ContactDestroy(contact* con);

对于结构体中的数组创建是要定长数组还是动态数组?
我们使用定长数组,虽然无法确定内容大小,但是根据常识,可以给出数组的最大容量


1.3.2 Seqlist.h

注意⚠️

CInfo只是在contact.h中的结构体重命名,但是别的文件不知道有这回事,所以不认识cinfo--->我们需要包含头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"contact.h"//包含头文件
#include<string.h>
//创建动态顺序表
//typedef int SLDataType;//方便以后修改数据类型,因为我们不一定每次都需要int类型

//替换
typedef struct CInfo SLDataType;//注意CInfo

1.3.3 contact.c

#include"Seqlist.h"
#include"contact.h"

//通讯录的初始化和销毁
void ContactInit(contact* con)
{
	SLInit(con);//直接调用顺序表的初始化
}
void ContactDestroy(contact* con)
{
	SLDestroy(con);//直接调用顺序表的销毁
}

1.3.4 text.c

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//销毁通讯录
	ContactDestroy(&con);
}
int main()
{
	contact01();
	return 0;
}

1.3.5 代码运行测试


我们发现疯狂报错,这是为什么呢?


例如我们先解决这个问题:原来的是int类型的,而新的SLDataType是struct类型的,所以==非法--->我们要修改


ps->a[I].name==x
......(一个一个比较)

这里为了方便,我们直接注释掉查找数据的相关代码


对于这个错误,我们还是把重命名修改一下,不要用CnInfo了(contact.h)

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include"contact.h"//包含头文件
//创建动态顺序表
//typedef int SLDataType;//方便以后修改数据类型,因为我们不一定每次都需要int类型

//替换
typedef struct ContactInfo SLDataType;

1.3.6 二次代码测试


1.4 添加+删除联系人👻

1.4.1 contatc.h

//添加+删除联系人
void ContactAdd(contact* pcon);
void ContactcDel(contact* pcon);

1.4.2 contact.c

//添加联系人
void ContactAdd(contact* pcon)
{
	//接下来要获取的数据都是CInfo结构体里我们设置的数据
	CInfo info;
	printf("请输入要添加的联系人的姓名:");
	scanf("%s", info.name);//name是数组名--->本来就是地址
	printf("请输入请输入要添加的联系人的性别:");
	scanf("%s", info.sex);
	printf("请输入要添加的联系人的年龄:");
	scanf("%d", &info.age);//age是int类型的数据--->取地址
	printf("请输入要添加的联系人的号码:");
	scanf("%s", info.phone);
	printf("请输入要添加的联系人的地址:");
	scanf("%s", info.addr);
	//数据获取到之后存储到info中
	//接下来,我们需要在顺序表中插入数据
	SLpushBack(pcon, info);//直接调用顺序表的尾插
}

//删除联系人
//由于删除/添加/查找联系人都需要判断联系人是否存在,所以我们把判断联系人是否存在单独写出来
int FindByName(contact* pcon, char name[])
{
	for (int i = 0; i < pcon->size; i++)
	{ 
		if (strcmp(pcon->a[i].name, name) == 0)//strcmp比较字符串大小
			return i;
	}
	return -1;
}

void ContactcDel(contact* pcon)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
	//这里直接要求输入联系人的姓名进行查找
	printf("请输入要删除的联系人的姓名:");
	//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	scanf("%s", name);
	//调用函数判断联系人是否存在
	//1.存在--->根据返回的下标删除--->即为调用顺序表的删除指定位置的数据
	//2.不存在--->说明要删除的联系人不存在
	int ret=FindByName(pcon, name);
	if (ret < 0)
	{
		printf("要求删除的联系人不存在!\n");
		return 1;
	}
	else
	{
		SLErase(pcon, ret);//调用顺序表的删除指定位置的数据
	}
}

1.4.3 tets.c

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//添加联系人
	ContactAdd(&con);
	ContactAdd(&con);
	ContactAdd(&con);
	//删除联系人
	ContactcDel(&con);
	//销毁通讯录
	ContactDestroy(&con);
}
int main()
{
	contact01();
	return 0;
}

1.4.4 代码运行测试


1.5 修改联系人🙉

1.5.1 contatc.h

//修改联系人
void ContactChange(contact* pcon);

1.5.2 contact.c

//修改联系人
void ContactChange(contact* pcon)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
    //这里直接要求输入联系人的姓名进行查找
	//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名:");
	scanf("%s", name);
	//调用函数判断联系人是否存在
//1.存在--->根据返回的下标修改
//2.不存在--->说明要修改的联系人不存在
	int ret = FindByName(pcon, name);
	if (ret < 0)
	{
		printf("要求修改的联系人不存在!\n");
		return 1;
	}
	else
	{
		//底层逻辑是顺序表--->在顺序表中修改对应的下标的结构体中的各项数据
		printf("请输入新的联系人的姓名:");
		scanf("%s", pcon->a[ret].name);//name是数组名--->本来就是地址
		printf("请输入请输入新的联系人的性别:");
		scanf("%s", pcon->a[ret].sex);
		printf("请输入新的联系人的年龄:");
		scanf("%d", &pcon->a[ret].age);//age是int类型的数据--->取地址
		printf("请输入新的联系人的号码:");
		scanf("%s", pcon->a[ret].phone);
		printf("请输入新的联系人的地址:");
		scanf("%s", pcon->a[ret].addr);
		printf("修改成功!\n");
	}
}

1.5.3 tets.c

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//添加联系人
	ContactAdd(&con);
	ContactAdd(&con);
	ContactAdd(&con);
	//删除联系人
	ContactDel(&con);
	//修改联系人
	ContactChange(&con);
	//销毁通讯录
	ContactDestroy(&con);
}
int main()
{
	contact01();
	return 0;
}

1.5.4 代码运行测试


但是,我们发现有时候修改联系人的时候,我们可能只需要修改年龄or地址单个数据,或者几个数据,不是全都要修改,所以要优化一下啊

1.5.5 contact.h优化🍎

我们可以添加菜单,让使用者选择要修改的项目,在原来的代码基础上修改,从而达到只修改1项或者几项的目的


//修改联系人
void ContactChange(contact* pcon)
{
	//我们需要使用联系人众多信息中的一项来查找联系人是否存在
	//这里直接要求输入联系人的姓名进行查找
	//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名:");
	scanf("%s", name);
	//调用函数判断联系人是否存在
//1.存在--->根据返回的下标修改
//2.不存在--->说明要修改的联系人不存在
	int ret = FindByName(pcon, name);
	if (ret < 0)
	{
		printf("要求修改的联系人不存在!\n");
		return 1;
	}
	else
	{
		int a = -1;
		do {
			printf("*******************************************\n");
			printf("*******************通讯录******************\n");
			printf("***********1.修改姓名 2.修改性别***********\n");
			printf("***********3.修改年龄 4.修改号码***********\n");
			printf("***********5.修改地址 6.退出修改***********\n");
			printf("请选择你的操作:\n");
			scanf("%d", &a);
			//底层逻辑是顺序表--->在顺序表中修改对应的下标的结构体中的各项数据
			switch (a)
			{
			case 1:
				printf("请输入新的联系人的姓名:");
				scanf("%s", pcon->a[ret].name);//name是数组名--->本来就是地址
				break;
			case 2:
				printf("请输入请输入新的联系人的性别:");
				scanf("%s", pcon->a[ret].sex);
				break;
			case 3:
				printf("请输入新的联系人的年龄:");
				scanf("%d", &pcon->a[ret].age);//age是int类型的数据--->取地址
				break;
			case 4:
				printf("请输入新的联系人的号码:");
				scanf("%s", pcon->a[ret].phone);
				break;
			case 5:
				printf("请输入新的联系人的地址:");
				scanf("%s", pcon->a[ret].addr);
				break;
			case 6:
				printf("退出修改联系人的界面!\n");
				break;
			default:
				printf("输入有误!请重新输入:\n");
				break;
			}
		} while (a != 6);
	}
}

1.5.6 test.c修改

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//添加联系人
	ContactAdd(&con);
	//ContactAdd(&con);
	ContactAdd(&con);
	//删除联系人
	//ContactDel(&con);
	//修改联系人
	ContactChange(&con);
	//销毁通讯录
	ContactDestroy(&con);
}
int main()
{
	contact01();
	return 0;
}

为了方便,我们就先注释掉删除联系人的操作,并且只添加2个联系人


1.5.7 二次代码运行测试


1.6 查看通讯录🥑

1.6.1 contatc.h

//查看通讯录
void ContactShow(contact* pcon);

1.6.2 contact.c

//查看通讯录
void ContactShow(contact* pcon)
{
	//打印通讯录存储的所有数据
	//为了更加好看--->我们先输出表头
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "号码", "地址");
	for (int i = 0; i < pcon->size; i++)
	{
		printf("%-4s %-4s %-4d %-4s %-10s\n",//表头对齐--->美观
			pcon->a[i].name,
			pcon->a[i].sex,
			pcon->a[i].age,
			pcon->a[i].phone,
			pcon->a[i].addr
			);
	}
}

1.6.3 tets.c

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//添加联系人
	ContactAdd(&con);
	ContactAdd(&con);
	ContactAdd(&con);
	//删除联系人
	ContactDel(&con);
	//修改联系人
	ContactChange(&con);
	//查看通讯录
	ContactShow(&con);
	//销毁通讯录
	ContactDestroy(&con);
}

int main()
{
	contact01();
	return 0;
}

1.6.4 代码运行测试


1.7 查找指定联系人👤

1.7.1 contatc.h

//查找指定联系人
void ContactFind(contact* pcon);

1.7.2 contact.c

//查找指定联系人
void ContactFind(contact* pcon)
{
//我们需要使用联系人众多信息中的一项来查找联系人是否存在
//这里直接要求输入联系人的姓名进行查找
//创建一个name数组存储要输入的姓名
	char name[NAME_MAX];
	printf("请输入要查找的联系人的姓名:");
	scanf("%s", name);
	//调用函数判断联系人是否存在
//1.存在--->根据返回的下标查找并打印出来
//2.不存在--->说明要查找的联系人不存在
	int ret = FindByName(pcon, name);
	if (ret < 0)
	{
		printf("要求查找的联系人不存在!\n");
		return 1;
	}
	else
	{
		printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "号码", "地址");
			printf("%-4s %-4s %-4d %-4s %-4s\n",//表头对齐--->美观
				pcon->a[ret].name,
				pcon->a[ret].sex,
				pcon->a[ret].age,
				pcon->a[ret].phone,
				pcon->a[ret].addr
			);
	}
}

1.7.3 tets.c

#include"Seqlist.h"
#include"contact.h"
//contact
void contact01()
{
	//创建+初始化通讯录
	contact con;
	ContactInit(&con);
	//添加联系人
	ContactAdd(&con);
	ContactAdd(&con);
	ContactAdd(&con);
	//删除联系人
	ContactDel(&con);
	//修改联系人
	ContactChange(&con);
	//查看通讯录
	ContactShow(&con);
	//查找指定联系人
	ContactFind(&con);
	//销毁通讯录
	ContactDestroy(&con);
}


int main()
{
	contact01();
	return 0;
}

1.7.4 代码运行测试


1.8 美观---菜单界面🏵️

为了更加美观,我们制作一个菜单界面


1.8.1 test.c

//为了界面更加美观--->创建菜单界面
void menu1()
{
	printf("***********************************************\n");
	printf("*********************通讯录********************\n");
	printf("***********1.添加联系人 2.删除联系人***********\n");
	printf("***********3.修改联系人 4.查找联系人***********\n");
	printf("***********5.查看通讯录 6.退出通讯录***********\n");
}
int main()
{
	int a = -1;
	//初始化+创建通讯录
	contact con;
	ContactInit(&con);
	//一系列操作
	do {
		menu1();
		printf("请选择你的操作:\n");
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactChange(&con);
			break;
		case 4:
			ContactShow(&con);
			break;
		case 5:
			ContactFind(&con);
			break;
		case 6:
			printf("退出通讯录界面!\n");
			break;
		default:
			printf("选择错误!请重新选择:\n");
			break;
		}
	} while (a != 6);
		//销毁通讯录
		ContactDestroy(&con);
	return 0;
}

1.9 通讯录📇代码运行测试


2. 顺序表经典算法

2.1 经典算法OJ题1: 移除元素🚨

2.1.1 题目


2.1.2 思路分析

解法1:遍历一遍数组,若值为val,执行删除操作

​​​​​​​


解法2:使用双指针

定义2个指针src=0和dst=0遍历数组

1)src指向的数据是val

src++;

2)src指向的数据不是val

src指向的数据赋给dst的位置

dst++;

src++;


2.1.3 代码实现

2.1.3.1 解法1
int removeElement(int* nums, int numsSize, int val){
int size=0;
for(int i=0;i<numsSize;i++)
{
if(nums[i]!=val)
{
    nums[size++]=nums[i];
}
}
return size;
}

2.1.3.2 解法2
int removeElement(int* nums, int numsSize, int val){
int src=0,dst=0;
while(src<numsSize)
{
    if(nums[src]==val)
    src++;
    else
    {
        nums[dst]=nums[src];
        dst++;
        src++;
    }
}
return dst;
}

2.2 经典算法OJ题2: 合并两个有序数组☎️

2.2.1 题目


2.2.2 思路分析



2.2.3 代码实现

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int l1=m-1,l2=n-1;
int l3=m+n-1;
while(l1>=0&&l2>=0)
{
    if(nums1[l1]>nums2[l2])
    nums1[l3--]=nums1[l1--];
    else
    {
        nums1[l3--]=nums2[l2--];
    }
}
while(l2>=0)
{
    nums1[l3--]=nums2[l2--];
}
}

3. 顺序表的问题及思考

1. 中间/头部的插⼊删除,时间复杂度为O(N) 

2. 增容需要申请新空间,拷⻉数据,释放旧空间。会有不⼩的消耗。

3. 增容⼀般是呈2倍的增⻓,势必会有⼀定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插⼊了5个数据,后⾯没有数据插⼊了,那么就浪费了95个数据空间。

思考:如何解决以上问题呢?

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

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

相关文章

旋转图像(C++解法)

题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在原地旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输…

Pytorch深度学习 - 学习笔记

文章目录 Pytorch深度学习1. Pytorch加载数据初认识2. TensorBoard3. Transforms常见的transform 4. torchvision中的数据集使用5. DataLoader使用6. 神经网络6.1 神经网络的基本骨架6.2 卷积层6.3 最大池化的使用6.4 非线性激活6.5 线性层及其他层6.6 小实战及Sequential 7. 损…

苹果手机内存清理怎么做?5招教你拯救内存!

大家的手机内存还能坚持多久呢&#xff1f;无论是什么牌子的手机&#xff0c;只要使用的时间越久&#xff0c;手机的内存必然会越来越小。如果不及时清理手机里的历史缓存、垃圾文件等数据&#xff0c;就会导致手机变得迟缓、卡顿。 那么&#xff0c;我们该怎么做呢&#xff1…

如何使用 GoGoCode 一键 Vue2 转换 Vue3

前言 从今年年初开始&#xff0c;项目开始升级优化&#xff0c;将之前的 Vue2 旧版本整体升级到 Vue3 版本。在重写了几个 Vue 文件后&#xff0c;我发现做的都是一些机械性的工作&#xff0c;效率低且重复性大。于是就试着搜索了一下有没有什么能够批量转换代码格式的工具&am…

SPE(Single Pair Ethernet)

以太网标准 讲SPE&#xff08;Single Pair Ethernet&#xff09;之前我们先了解一下以太网标准&#xff1a; CategoryStandardCable length(m)Data rateDuplex CapabilityWiresFast Ethernet10/100BASE-T10010Mb/s to 100Mb/sFull4Gigabit Ethernet1000/10GBAST-T1001Gb/s to …

UOS系统无法开机问题解决

1、问题截图1 &#xff1a; 2、问题截图2 &#xff1a; 3、问题截图3&#xff1a; 解决方案&#xff1a; 修复磁盘无效&#xff0c;建议拷贝数据&#xff0c;还原系统 请先拷贝数据 进live模式在root a或root b 或系统盘找到Home文件夹里-找到用户名-里面就是用户的数据&am…

四川竹哲电商:抖店怎么修改经营类目?

抖店是抖音推出的一款电商工具&#xff0c;通过抖店可以帮助商家在抖音上开展经营活动。在抖店平台上&#xff0c;商家需要选择经营类目&#xff0c;以便在相应的领域展示商品和提供服务。然而&#xff0c;有时候商家可能需要修改经营类目&#xff0c;以适应经营策略调整或扩大…

什么是无磁远传水表?工作原理是怎样的?

无磁远传水表是一种新型的智能水表&#xff0c;与传统水表相比&#xff0c;它具有更高的精度和可靠性&#xff0c;并且可以实现远程读数和控制。那么&#xff0c;无磁远传水表的工作原理是怎样的呢?下面&#xff0c;小编来为大家介绍下什么是无磁水表?它的工作原理是怎样的&a…

MySQL 三大日志(bin log、redo log、undo log)

redo log redo log (重做日志) 是 InnoDB 存储引擎独有的&#xff0c;它让 MySQL有了崩溃恢复的能力&#xff0c;是事务中实现 持久化的重要操作 比如 MySQL 实例宕机了&#xff0c;重启时&#xff0c;InnoDB 存储引擎会使用 redo log 恢复数据&#xff0c;保证数据的持久性与…

数字孪生技术:重塑企业经营的未来

在当今数字化时代&#xff0c;企业经营面临了前所未有的挑战和机遇。数字孪生技术作为新一代数字化工具&#xff0c;正在成为企业走向成功的关键。数字孪生是一种通过数字模型在虚拟世界中模拟和反映物理实体、过程和系统的技术&#xff0c;它为企业经营带来了许多重要的帮助。…

Sourcetree突然打不开,双击打开,图片闪一下就没反应了

解决方案如下&#xff1a; 1.点击图标&#xff0c;右键点击“打开文件所在位置 2.返回上一级&#xff0c;找到Atlassian文件夹 3.进入此文件夹下&#xff0c;删除SourceTree.exe_Url文件夹 4.再双击桌面的Sourcetree图标&#xff0c;可以正常打开。 最近刚遇到此问题&#x…

【广州华锐互动】智慧水务3D可视化数字孪生大屏定制开发

污水处理流程的复杂性需要一种有效的方法进行理解和优化。传统的2D图表和文字描述方法往往无法全面、直观地展示污水处理的各个环节。然而&#xff0c;智慧排水3D数字化管控系统可以为污水处理流程提供更深入、更全面的理解&#xff0c;从而帮助改进污水管理。 首先&#xff0c…

Vue2双向数据绑定的原理

Vue.js 是采用数据劫持结合发布者-订阅者模式的方式&#xff0c;通过Object.defineProperty()来劫持各个属性的setter&#xff0c;getter&#xff0c;在数据变动时发布消息给订阅者&#xff0c;触发相应的监听回调 Vue双向数据绑定主要有以下几个步骤&#xff1a; 模板解析 事件…

为何说只有 1 种实现线程的方法?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 今天我们来学习为什么说本质上只有一种实现线程的方式&#xff1f;实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里&#xff1f; 实现线程是并发编程中基础中的基础&#xff0c;因为我们必须要先实现多线程…

虹科活动 | 探索全新AR应用时代,虹科AR VIP研讨会广州场回顾!

文章来源&#xff1a;虹科数字化AR 阅读原文&#xff1a;https://mp.weixin.qq.com/s/7tmYR42Tw5XLn70fm8Nnew 主题演讲 本次研讨会&#xff0c;虹科特邀 “工业AR鼻祖” 美国Vuzix公司的首席应用工程师郑慎方先生进行主题演讲&#xff0c;并邀请到了各界的专业人士和企业代表参…

ESRI ArcGIS Pro 3.0-3.0.2图文安装教程及下载

ArcGIS 是由美国著名的地理信息系统公司 Esri 开发的一款地理信息系统软件。ArcGIS Pro是一款功能强大的单桌面 GIS 应用程序&#xff0c;是在桌面上创建和处理空间数据的基本应用程序。ArcGIS Pro支持数据可视化和数据高级分析&#xff0c;可以创建 2D 地图和3D 场景。它支持跨…

无需公网IP,通过内网穿透轻松搭建微信公众号开发本地调试环境!

文章目录 前言1. 配置本地服务器2. 内网穿透2.1 下载安装cpolar内网穿透2.2 创建隧道 3. 测试公网访问4. 固定域名4.1 保留一个二级子域名4.2 配置二级子域名 5. 使用固定二级子域名进行微信开发 前言 在微信公众号开发中&#xff0c;微信要求开发者需要拥有自己的服务器资源来…

如何建立风险、内控与合规三位一体的管控体系?

为指导企业开展风险管理工作&#xff0c;进一步提高管理水平&#xff0c;增强竞争力&#xff0c;促进稳步发展&#xff0c;自2006年开始&#xff0c;我国国资委、财政部等相关部委借鉴COSO理论及国际上影响较大的风险管理和内部控制标准&#xff0c;结合国内的实际情况&#xf…

构建跨平台应用程序:Apollo在移动开发中的应用

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

软件工程与计算(二十二)软件开发过程模型

&#xff08;自顶向下&#xff0c;逐层细化&#xff09; 目录 一.软件开发的典型阶段 1.需求工程 2.软件设计 3.软件构造 4.软件测试 5.软件交付 6.软件维护 二.软件生命周期模型 三.软件过程模型 四.构建-修复模型 五.瀑布模型 六.增量迭代模型 七.演化模型 八…