C语言详解【通讯录的实现】

news2024/11/23 15:48:19

前言:
在之前的学习中我们已经了解了结构体的一些知识,有了之前的知识的储备,在这里我们就可以尝试通讯录的实现。

目录

  • 问题描述
  • 基本流程
  • 前期的准备工作
  • 实现过程
    • 第一阶段
    • 第二阶段
    • 第三阶段
      • 1.增加联系人
      • 2.删除联系人
      • 3.打印通讯录
      • 4.查找指定联系人
      • 5.修改联系人
      • 6.排序
      • 7.销毁通讯录
  • 代码以及总结
    • test.c代码
    • contact.c代码
    • contact.h代码

问题描述

用c语言来进行通讯录的基本实现。

基本流程

实现通讯录的基本流程分为以下几步:
1,首先通讯录是用来存放联系人的信息,一个人信息有很多,例如(姓名,性别,年龄等),所以这里使用我们之前学过的结构体来存放联系人的信息。
2,一个通讯录所包含的联系人肯定不止一个,所以需要一个数组来存放,因为创建了联系人结构体的类型,所以需要使用相同结构体类型的数组来存放多个人的信息。(这里采用了动态内存的方式来存储联系人,传回来的为动态内存的首地址,也可以将其看为一个结构体类型的数组来使用)
3,通讯录的主要功能:增删查改联系人,打印通讯录,排序以及退出通讯录等功能。
增加联系人:往数组里面放元素。
删除联系人:找到联系人,将需要删除的联系人后面的联系人前移一位实现覆盖删除。
查找联系人:一般按名字查找。
修改联系人:找到联系人的位置,在相同位置重新录入信息实现覆盖修改。
打印通讯录:打印数组,把我们录入的展示出来。
联系人排序:选择用名字排序还是年龄排序或者其他信息排序,可以使用qsort函数来实现(这个函数在下期我会拿出来给大家细讲)。
退出:当我们完成我们想要的工作后便退出通讯录
4,使用动态内存开辟的方法来储存联系人,节约内存。
5,使用文件操作来保存信息和写入信息,使系统运行时自动载入已保存的信息。

前期的准备工作

首先我们还是在一个项目中创建三个文件,两个源文件,一个文件存放主函数,一个文件来存放通讯录的实现函数,还有一个头文件来声明函数。
在这里插入图片描述

实现过程

第一阶段

首先我们还是先搭建主体的框架,写一个菜单来实现相应的功能:

void menu()
{
	printf("**************************************\n");
	printf("*****   1. add      2. del       *****\n");
	printf("*****   3. search   4. modify    *****\n");
	printf("*****   5. show     6. sort      *****\n");
	printf("*****   0. exit                  *****\n");
	printf("**************************************\n");
}

上面主函数内部的分支循环 case 中我们输入的字符是为了便于理解,但是这样是没办法实现最开始的以数字来进行菜单选项的初衷的,所以我们需要枚举这些选择功能来达到这样的一个效果:

enum option
{
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	EXIT
};

写好之后我们可以看出结果如下:
在这里插入图片描述
菜单写出来之后,自然而然我们要让玩家能够根据信息输入相应的数字进行游戏,效果图如下:

do
	{
		menu();
		printf("请选择数字->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
	//cese ADD:
			AddContact(&per);
			break;
		case 2:
	//cese DEL:
			DelContact(&per);
			break;
		case 3:
	//cese SEARCH:
			SearchContact(&per);
			break;
		case 4:
	//cese MODIFY:
			ModifyContact(&per);
			break;
		case 5:
	//cese SHOW:
			ShowContact(&per);
			break;
		case 6:
	//cese SORT:
			SortContact(&per);
			break;
		case 0:
	//cese EXIT:
			DestroyContact(&per);
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);

到此我们前期的框架基本上已经搭建好了。紧接着就是建立我们的通讯录了,对我们想要的功能进行依次的实现。

第二阶段

第一步:我们需要定义联系人的一些属性,定义了一个结构体PeoInfo,简单分析不难发现,这个结构体表示的就是一个人的信息。姓名、电话、地址、年龄、性别这几条信息存放在一个字符数组中:

struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	int age;
	char addr[MAX_ADDR];
};

第二步:就是定义通讯录的内容,而在这一步为了高效的实现的日常生活动态增长的一个情况,我们使用动态增长的一个版本。结构体有三个成员,一个是结构体数组,数组中的每个元素就是上面创建的结构体。还有一个元素是整型变量sz。上一个结构体代表的是一个人的信息,最后就是满足动态增长而设置的判断,而通讯录的目的就是把多个人的信息存放在一起,所以这个结构体Contact所代表的的就是我们的通讯录:

struct Contact
{
	struct PeoInfo* data;//
	int sz;              //
	int capacity;        //当前的容量
};

紧接着就是为了实现我们上面结构体内部的这些内容,我们需要进行一些声明:

#define MAX_NAME 20
#define MAX_SEX  10
#define MAX_TELE 12
#define MAX_ADDR 30
#define MAX 100

#define DEFAULT_SZ 3
#define INC_SZ 2

到此对通讯录的建立就完成了,接下来我们要做的便是关键一步对通讯录进行相应的初始化操作以及功能实现

第三阶段

首先进行的是初始化操作(后面都以动态增长为例):
初始化函数InitContact,初始化通讯录,使用malloc(动态内存开辟函数)开辟动态内存来存放联系人的信息,sz为有效联系人个数,capacity为通讯录的最大容量

void InitContact(struct Contact* pc)
{
	assert(pc); //断言
	pc->data = (struct PeoInfo*)malloc(DEFAULT_SZ *sizeof(struct PeoInfo));
	if (pc->data == NULL)
	{
		printf("InitContact fail");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;

}

接下来就是实现相应功能的功能函数了。

1.增加联系人

//动态增长联系人
void AddContact(struct Contact* pc)
{
	assert(pc);

	if (0 == check_capacity(pc))
	{
		return;
	}
	//增加人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("成功增加联系人\n");
}

添加联系人就是往开辟好的内存里面存放联系人的结构体信息,在每次添加之前需要先判断通讯录是否已经满了,若是满了需要增容,使用realloc来重新分配动态内存,这里每次满了之后默认增加两个联系人的空间,成功增加联系人之后总数加1,sz+1。检查容量函数如下:

int  check_capacity(struct Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(struct PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INC_SZ;
			printf("成功增容");
				return 1;
		}
		else
		{
			printf("AddContact fail");
			return 0;
		}
	}
	else
			return 1;
}

2.删除联系人

删除之前需要找到联系人的位置,因为这个函数我们不用让外面看到,所以用static来修饰这个函数,这样的话这个函数就只能在该源文件内部使用。该函数接收两个参数,一个是通讯录结构体,一个是要查找的成员名称。这里通过名字查找代码如下:

static int FindByName(const struct Contact* pc, char name[])
{
	for(int i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}

查找的过程采用遍历的方式,让通讯录中的每一个成员的名字来和要查找的成员名字来作比较,这里用到字符串比较函数strcmp,当这两个字符串相等时,该函数返回值为0,第一个大于第二个返回一个大于0的值,小于则返回一个小于0的值。当判断函数的返回值等于0时,说明找到了要查找的元素,紧接着返回该元素的下标。如果找不到返回-1即可,在之前我们也已经介绍过这个函数。
主体函数如下:

//删除指定联系人
void DelContact(struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入删除的人的姓名:->");
	scanf("%s", name);
	//判断输入是否合理
	int ret=FindByName(pc, name);
	if (ret == -1)
		printf("删除的人不存在,请重新输入\n");
	else
	{
		int j = 0;
		for (j = ret; j < pc->sz - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
}

删除联系人就是找到需要删除的联系人,然后将后面的联系人都往前移动一位,这里最后一位联系人可能会被后面空白覆盖,所以判断循环的条件改为 j<sz-1,pc->data[i] = pc->data[i + 1];此时j+1最大值位sz-1就是最后一个联系人的位置,当sz-1覆盖到sz-2时,原位置上的数据还是存在的,但是已经不是有效的联系人了,打印时不打印就可以,移动完成之后,总数减1即sz-1。

3.打印通讯录

打印的时候我们可以估算一下各个信息的长度,然后打印。%10s的意思就是打印的空间占10个字符型空间。由于通讯录中可能有多条信息,所以打印的时候采用一个循环来打印,打印的次数就是有效信息数sz的值。

//打印通讯录
void ShowContact(const struct Contact* pc)
{
	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
			                                        pc->data[i].sex,
			                                        pc->data[i].age,
			                                        pc->data[i].tele,
			                                        pc->data[i].addr);
	}
}

4.查找指定联系人

先输入要查找人的姓名,然后调用查找函数,观察返回值,如果找不到,就打印查找的人不存在。如果找到,返回这个人的下标,我们就可以通过这个人的下标来把这个人的信息展示出来。

//查找指定联系人
void SearchContact(const struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入查找的人的姓名:->");
	scanf("%s", name);
	//判断输入信息是否存在
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("查找的人不存在,请重新输入\n");
	else
	{
		printf("%-20s\t%-10s\t%-20s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-20s\t%-10s\t%-20s\t%-12s\t%-30s\n", pc->data[ret].name,
			                                        pc->data[ret].sex,
			                                        pc->data[ret].age,
			                                        pc->data[ret].tele,
			                                        pc->data[ret].addr);
	}
}

5.修改联系人

这一步是先进行查找操作,先找到联系人,然后在这个联系人的位置重新录入一遍信息即可,代码如下:

//修改联系人
void ModifyContact(struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入修改的人的姓名:->");
	scanf("%s", name);
	//判断输入信息是否存在
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("修改的人不存在,请重新输入\n");
	else
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);

		printf("修改成功\n");
	}
}

6.排序

我们要根据成员的某一个信息来排序,我们可以使用姓名和年龄来排序,这里我们使用qsort函数来进行相关操作:

//通过名字进行排序
int CmpByName(const void* n1, const void* n2)
{
	return (((struct PeoInfo*)n1)->name - ((struct PeoInfo*)n2)->name);

}
//通过年龄进行排序
int CmpByAge(const void* age1, const void* age2)
{
	return (((struct PeoInfo*)age1)->age - ((struct PeoInfo*)age2)->age);

}

//排序
void SortContact(struct Contact* pc)
{
	//qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);

}

7.销毁通讯录

使用完毕之后,应该销毁动态内存开辟的空间,防止动态内存,代码如下:

//销毁
void DestroyContact(struct Contact* pc)
{
	free(pc->data);
    pc->data=NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

代码以及总结

test.c代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"


void menu()
{
	printf("**************************************\n");
	printf("*****   1. add      2. del       *****\n");
	printf("*****   3. search   4. modify    *****\n");
	printf("*****   5. show     6. sort      *****\n");
	printf("*****   0. exit                  *****\n");
	printf("**************************************\n");
}


enum option
{
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	EXIT
};

int main()
{
	int input = 0;

	//建立通讯录
	struct Contact per;
	//初始化通讯录
	InitContact(&per);

	do
	{
		menu();
		printf("请选择数字->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
	//cese ADD:
			AddContact(&per);
			break;
		case 2:
	//cese DEL:
			DelContact(&per);
			break;
		case 3:
	//cese SEARCH:
			SearchContact(&per);
			break;
		case 4:
	//cese MODIFY:
			ModifyContact(&per);
			break;
		case 5:
	//cese SHOW:
			ShowContact(&per);
			break;
		case 6:
	//cese SORT:
			SortContact(&per);
			break;
		case 0:
	//cese EXIT:
			DestroyContact(&per);
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

contact.c代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"



//初始化通讯录
//void InitContact(struct Contact* pc)
//{
//	assert(pc);
//	pc->sz =0
//	memset(pc->data, 0, MAX * sizeof(struct  PeoInfo));
//
//}
//动态的初始化版本
void InitContact(struct Contact* pc)
{
	assert(pc);
	pc->data = (struct PeoInfo*)malloc(DEFAULT_SZ *sizeof(struct PeoInfo));
	if (pc->data == NULL)
	{
		printf("InitContact fail");
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;

}
//静态增加联系人
//void AddContact(struct Contact* pc)
//{
//	assert(pc);
//
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满,无法添加数据\n");
//		return;
//	}
//
//	//增加人的信息
//	printf("请输入名字:>");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入性别:>");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入年龄:>");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入电话:>");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:>");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("成功增加联系人\n");
//}

int  check_capacity(struct Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(struct PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INC_SZ;
			printf("成功增容");
				return 1;
		}
		else
		{
			printf("AddContact fail");
			return 0;
		}
	}
	else
			return 1;
}
//动态增长联系人
void AddContact(struct Contact* pc)
{
	assert(pc);

	if (0 == check_capacity(pc))
	{
		return;
	}

	//增加人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("成功增加联系人\n");
}

//销毁
void DestroyContact(struct Contact* pc)
{
	free(pc->data);
    pc->data=NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

//打印通讯录
void ShowContact(const struct Contact* pc)
{
	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
			                                        pc->data[i].sex,
			                                        pc->data[i].age,
			                                        pc->data[i].tele,
			                                        pc->data[i].addr);
	}
}

static int FindByName(const struct Contact* pc, char name[])
{
	for(int i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}

//删除指定联系人
void DelContact(struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入删除的人的姓名:->");
	scanf("%s", name);
	//判断输入是否合理
	int ret=FindByName(pc, name);
	if (ret == -1)
		printf("删除的人不存在,请重新输入\n");
	else
	{
		int j = 0;
		for (j = ret; j < pc->sz - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
}

//查找指定联系人
void SearchContact(const struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入查找的人的姓名:->");
	scanf("%s", name);
	//判断输入信息是否存在
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("查找的人不存在,请重新输入\n");
	else
	{
		printf("%-20s\t%-10s\t%-20s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-20s\t%-10s\t%-20s\t%-12s\t%-30s\n", pc->data[ret].name,
			                                        pc->data[ret].sex,
			                                        pc->data[ret].age,
			                                        pc->data[ret].tele,
			                                        pc->data[ret].addr);
	}
}

//修改联系人
void ModifyContact(struct Contact* pc)
{
	char name[MAX_NAME];
	printf("请输入修改的人的姓名:->");
	scanf("%s", name);
	//判断输入信息是否存在
	int ret = FindByName(pc, name);
	if (ret == -1)
		printf("修改的人不存在,请重新输入\n");
	else
	{
		printf("请输入名字:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入电话:>");
		scanf("%s", pc->data[ret].tele);
		printf("请输入地址:>");
		scanf("%s", pc->data[ret].addr);

		printf("修改成功\n");
	}
}

//通过名字进行排序
int CmpByName(const void* n1, const void* n2)
{
	return (((struct PeoInfo*)n1)->name - ((struct PeoInfo*)n2)->name);

}
//通过年龄进行排序
int CmpByAge(const void* age1, const void* age2)
{
	return (((struct PeoInfo*)age1)->age - ((struct PeoInfo*)age2)->age);

}

//排序
void SortContact(struct Contact* pc)
{
	//qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByName);
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);

}


contact.h代码

#pragma once
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#define MAX_NAME 20
#define MAX_SEX  10
#define MAX_TELE 12
#define MAX_ADDR 30
#define MAX 100

#define DEFAULT_SZ 3
#define INC_SZ 2

struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	int age;
	char addr[MAX_ADDR];
};

//静态增长版本
//struct Contact
//{
//	struct PeoInfo data[MAX];
//	int sz;
//};

//动态增长版本
struct Contact
{
	struct PeoInfo* data;//
	int sz;              //
	int capacity;        //当前的容量
};


//初始化通讯录
void InitContact(struct Contact* pc);

//增加联系人
void AddContact(struct Contact* pc);

//显示通讯录的信息
void ShowContact(const struct Contact* pc);

//删除联系人
void DelContact(struct Contact* pc);

//查找联系人
void SearchContact(const struct Contact* pc);

//修改联系人
void ModifyContact(struct Contact* pc);

//排序
void SortContact(struct Contact* pc);

//销毁
void DestroyContact(struct Contact* pc);


总结:
以上就是关于通讯录的全部知识与介绍,大家最重要的是把整体思路捋清楚,有个大概的方向,然后慢慢去实现。

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

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

相关文章

高等数学(第七版)同济大学 习题11-7 个人解答

高等数学&#xff08;第七版&#xff09;同济大学 习题11-7 函数作图软件&#xff1a;Mathematica 1.试对曲面Σ&#xff1a;zx2y2&#xff0c;x2y2≤1&#xff0c;Py2&#xff0c;Qx&#xff0c;Rz2验证斯托克斯公式.\begin{aligned}&1. \ 试对曲面\Sigma&#xff1a;zx^…

yolov5+车道线检测

目标检测与车道线检测在自动驾驶以及车辆定位中起着重要的辅助作用&#xff0c;是环境感知中不可缺少的一个部分。基于深度学习的车道线检测方法近年来也在不断的提升&#xff0c;比如论文&#xff1a;Ultra Fast Deep Lane Detection with HybridAnchor Driven Ordinal Classi…

Allegro如何Wavie DRC操作指导

Allegro如何Wavie DRC操作指导 在做PCB设计的时候,会因为规则设置的原因,导致出现很多DRC,不方便检查,Allegro支持直接Waive掉正常DRC,方便检查,如下图 芯片中心需要打过孔方便散热,但是这些过孔的DRC是不需要显示的 具体操作如下 选择Display选择 Waive DRCs

数据结构与算法3—栈

1. 栈的定义 栈&#xff0c;也叫堆栈&#xff0c;是最常用也是最重要的数据结构之一。栈(Stack)是限定仅在表的一端进行插入或删除操作的线性表&#xff0c;通常称插入、删除的这一端为栈顶(Top)&#xff0c;另一端为栈底(Bottom)。当表中没有元素时称为空栈。栈操作的特点&am…

【服务器数据恢复】StorNext文件系统数据恢复案例

服务器数据恢复环境&#xff1a; 昆腾系列存储&#xff0c;9个磁盘柜&#xff0c;每个磁盘柜配置24块硬盘。其中8个磁盘柜用于存储数据&#xff0c;1个磁盘柜用于存储元数据。上层使用的是StorNext文件系统。 存储元数据的磁盘柜中24块磁盘的分配情况&#xff1a;8组RAID1阵列1…

1361. 验证二叉树

目录题目思路代码题目 二叉树上有 n 个节点&#xff0c;按从 0 到 n - 1 编号&#xff0c;其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。 只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时&#xff0c;返回 true&#xff1b;否则返回 false。 如果节点…

开发小程序遇到的问题

1、小程序授权定位时报错 原因&#xff1a; 需要授权 scope.userLocation、scope.userLocationBackground 时必须配置地理位置用途说明。 解决&#xff1a; 在app.json中&#xff0c;根据开发文档的提示&#xff0c;将下面的代码添加在与pages同级下 "permission": {…

16年经验的通信行业测试人,后悔入错行了吗?

屏幕前的读者对于一个行业的兴衰有什么看法呢&#xff1f;非常很现实的说&#xff0c;我们所处的行业直接关系着每个人的收入&#xff0c;处于行业的不同生命周期内&#xff0c;我们拿到的钱也会不一样。下面用本人所处的行业举个例子。工作经历初入通信行业从我进入通信行业的…

什么是SPI?SPI的优点有哪些?

1、什么是SPI&#xff1f; SPI是串行外设接口&#xff08;Serial Peripheral Interface&#xff09;的缩写&#xff0c;是Motorola公司推出的一种同步串行接口技术&#xff0c;是一种高速、全双工、同步的通信总线。 2、SPI优点 支持全双工通信通信简单数据传输速率块 3、缺…

案例分析中可能的考点1:招投标程序

招投标程序&#xff1a; &#xff08;1&#xff09;投标方不满足资质要求&#xff1b; &#xff08;2&#xff09;投标过程不满足时间要求&#xff1b; &#xff08;3&#xff09;招标公告内容或过程不满足要求&#xff1b; &#xff08;4&#xff09;评标人员不满足组成要求&a…

【数据结构与算法】二叉树的非递归前中后序遍历

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…

WebSphere8 批量安装和制作介质服务器

WAS 8.5 介质准备 1、安装install manager 2、安装IBM Packaging Utility unzip pu.offering.disk.linux_1.5.3000.20120531_2025.zip cd disk_linux/InstallerImage_linux ./consoleinst.sh 跟着向导安装。 3、安装PU mkdir pu cd pu unzip ../pu_1.5.3.zip ./imcl i…

如何使用集成在 SharePoint 中的开源 ONLYOFFICE 文档替代微软 Office

ONLYOFFICE 文档是一款开源的办公套件&#xff0c;在 GNU AGPL v3.0 下分发。它包括基于网络的查看器和协作编辑器&#xff0c;可用于处理文本文档、电子表格和演示文稿&#xff0c;与 OOXML 格式高度兼容。 ONLYOFFICE 文档可以与多种云服务集成&#xff0c;如 Nextcloud、ow…

仅CPU服务器pytorch ,torch_geometric安装配置

写在开头&#xff0c;做了整整三年的多组学数据分析&#xff0c;各种模式动物、组织、细胞系的各种组学数据&#xff0c;该怎么串联成我的论文&#xff1f;就是我要开启深度学习小白模式了。 万种流程先从环境配置开始&#xff0c;先说说环境&#xff0c;其实当家的有多GPU超大…

儿童护眼灯哪个好?四款儿童护眼台灯测评

儿童护眼灯在孩子的学习过程中起到了很重要的作用&#xff0c;53.7%的青少年们都有近视的现象&#xff0c;而好的台灯不仅照明非常柔和&#xff0c;而且对眼睛没有刺激和伤害&#xff0c;护眼灯相比传统电灯&#xff0c;一是古县更加明亮且可以调节&#xff0c;二是有护眼技术的…

HANA 的 calculation view出现模糊关联 ambiguous join

一旦我们用了join&#xff0c;那就会有个Analytic Engine分析引擎来确保不是唯一连接的时候&#xff0c;关键值不会被重复。 啥是模糊关联&#xff1f; 一般来讲关联基数是1&#xff1a;n, 或者n:1,或者 m:n都是。 以上两个关联&#xff0c;结果集如下&#xff1a; 这时候&a…

php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07

php学习笔记-php会话控制及web常用的预定义变量-day071、$_REQUEST2、$_SERVER3、$_COOKIE3.1 cookie的内容3.2 cookie的分类3.3 php中cookie的使用3.4 cookie自动登录小demo4、$SESSION4.1 session的工作原理4.2 session的使用4.2.1 修改php.ini中的session配置4.2.2 开启sess…

Android 深入系统完全讲解(13)

3 编译过程讲解 1 系统的编译过程 Android 的编译使用的 Makefile&#xff0c;推荐大家使用《GNU make 中文手册》&#xff0c;这本书有电子版&#xff0c;非常方便&#xff0c;主要是要理解清楚 Makefile 的规则&#xff0c;编译策略&#xff0c;可以通过写简单的编译机制&am…

【Java项目推荐】值得写到简历上的项目--黑马点评

优惠卷秒杀前言优惠券秒杀实现优惠券秒杀下单超卖问题一人一单分布式锁redis中加锁的一些特殊情况手动实现分布式锁分布式锁误删情况1分布式锁误删情况2lua脚本解决多条命令的原子性问题Redisson秒杀优化异步秒杀思路基于redis完成秒杀资格判断基于阻塞队列实现异步下单总结Red…

70、SSDNeRF: Semantic Soft Decomposition of Neural Radiance Fields

简介 官网&#xff1a;https://www.siddhantranade.com/research/2022/12/06/SSDNeRF-Semantic-Soft-Decomposition-of-Neural-Radiance-Fields.html SSDNeRF&#xff0c;将语义信号与场景的辐射信号联合编码&#xff0c;提供了场景的软分解为语义部分&#xff0c;能够正确编码…