【数据结构】二叉树(一)

news2024/11/16 13:49:29

目录

一、树的概念及结构

  1、树的概念

  2、树的相关概念

  3、树的表示

二、二叉树概念及结构

  1、二叉树的概念

  2、特殊二叉树

  3、二叉树的性质

  4、二叉树的存储结构

     4.1 顺序存储结构

     4.2 链式存储结构

三、二叉树顺序结构及实现

  1、二叉树的顺序结构

  2、堆的概念及结构

  3、堆的实现

     3.1 堆的结构与声明

     3.2 堆的向下调整算法

     3.3 堆的向上调整算法

     3.4 堆的创建

     3.5 堆的初始化

     3.6 堆的插入

     3.7 堆的删除

     3.8 堆顶元素数据

     3.9 堆的数据个数

     3.10 堆的销毁

     3.11 堆的判空

  4、堆的应用

     4.1 堆排序

     4.2 TOP-K 问题


一、树的概念及结构

  1、树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。

  • 有一个特殊的结点,称为根结点,根节点没有前驱结点;
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti (1<= i <= m) 又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继 因此,树是递归定义的。

注意:树形结构中,子树之间不能有交集,否则就不是树形结构。

前两颗树都出现了相交情况,所以不是树的结构,最后一个没有相交,因此是一棵树。 

  2、树的相关概念

 

  • 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6;
  • 叶节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点;
  • 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点;
  • 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点;
  • 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6;
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  • 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4;
  • 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先;
  • 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙; 

  3、树的表示

树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,既然保存值域,也要保存结点和结点之间 的关系,实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法 等。我们这里就简单的了解其中最常用的孩子兄弟表示法。

typedef int DataType;
struct Node
{
     struct Node* _firstChild1;   // 第一个孩子结点
     struct Node* _pNextBrother;  // 指向其下一个兄弟结点
     DataType _data;              // 结点中的数据域
};

如下图所示: 

二、二叉树概念及结构

  1、二叉树的概念

二叉树是一种特殊的树,其特点就是每个结点最多有两棵子树(即二叉树中不存在度大于2的结点),二叉树是 n (n>=0)个结点的有限集合:

  • 二叉树为空;
  • 由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

 注意:对于任意的二叉树都是由以下几种情况复合而成的:

  2、特殊二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是 说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K 的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对 应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。(其实就是前N-1层是满的,最后一层可以不满,但是必须从左到右连续)

  3、二叉树的性质

  1.  若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^{i-1}个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^{h}-1 .
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为n_{0} , 度为2的分支结点个数为 ,则有n_{0} = n_{2}+1.
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度, h=log_{2}(n+1) (ps:log_{2}(n+1)是log以2 为底,n+1为对数).
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对 于序号为i的结点有:

            (1)若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点;

            (2)若2i+1<n, 左孩子序号:2i+1, 2i+1 >= n , 否则无左孩子;

            (3)若2i+2<n, 右孩子序号:2i+2, 2i+2 >= n , 否则无右孩子;

  4、二叉树的存储结构

     4.1 顺序存储结构

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树

     4.2 链式存储结构

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是 链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所 在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面课程 学到高阶数据结构如红黑树等会用到三叉链。

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
     struct BinTreeNode* _pLeft;  // 指向当前节点左孩子
     struct BinTreeNode* _pRight; // 指向当前节点右孩子
     BTDataType _data;            // 当前节点值域
}
// 三叉链
struct BinaryTreeNode
{
     struct BinTreeNode* _pParent; // 指向当前节点的双亲
     struct BinTreeNode* _pLeft;   // 指向当前节点左孩子
     struct BinTreeNode* _pRight;  // 指向当前节点右孩子
     BTDataType _data;             // 当前节点值域
};

三、二叉树顺序结构及实现

  1、二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段

  2、堆的概念及结构

对于一个连续数组,把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足所有的父亲结点都大于(小于)它的孩子结点,则称为大堆(或小堆)。将根节点最大的堆叫做最大堆或大根堆根节点最小的堆叫做最小堆或小根堆

堆的性质:

(1)堆中某个节点的值总是不大于或不小于其父节点的值;

(2)堆总是一棵完全二叉树。

  3、堆的实现

     3.1 堆的结构与声明

堆的结构,它是用数组来实现的。堆的结构体中还包含了堆的数据大小,及堆的容量大小。 

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;  
	int size;      
	int capacity;   
}Heap;

     3.2 堆的向下调整算法

思路:因为本文是建的小堆,如果parent  > child ,就互换位置。

首先要找到 child ,根据上面图片中孩子和父亲下标的对应关系就能找到,然后要确保 child < n(n代表数组的大小),在循环体内部,默认指的是左孩子,经过确保右孩子存在且右孩子小于左孩子,++child 就跳转到右孩子,接下来就可以正常比较孩子节点和父亲节点的大小,在进行交换。

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(HPDataType* a, int n, int parent)//n为数组的大小
{
	int child = parent * 2 + 1;//左孩子
	while (child < n)
	{
		//确认child指向小的那个孩子
		if (child + 1 < n && a[child + 1] < a[child])//child+1 < n 右孩子存在的情况且右孩子更小
		{
			++child;//默认指向左孩子,++child就指向右孩子
		}
		//(小堆) 父亲大于孩子,交换,继续向下调整
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;//父亲小于孩子,跳出循环
		}
	}
}

     3.3 堆的向上调整算法

思路:因为本文建的是小堆,如果 child  < parent 时,就向上进行交换。

首先要找到它的父亲,然后要保证 child > 0 ,才能够进入循环,进行parent 和 child 的比较。

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void Adjustup(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//小堆
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

     3.4 堆的创建

建堆的时间复杂度为O(N)。

void HeapCreate(Heap* php, HPDataType* a, int n)
{
	assert(php);
	//扩容
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);
	php->size = php->capacity = n;
	//建堆算法
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(php->a, n, i);
	}
}

     3.5 堆的初始化

void HeapInit(Heap* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
}

     3.6 堆的插入

思路:因为堆的存储结构是数组,所以堆的插入是在尾部插入,然后向上调整,直至最后成为小堆。假设在尾部插入一个元素10。

void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	//扩容
	if (php->size == php->capacity)
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}
	php->a[php->size] = x;
	php->size++;
	//堆向上调整
	Adjustup(php->a, php->size - 1);
}

     3.7 堆的删除

思路:删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据进行交换,然后删除数组最后一个数据,再进行向下调整算法。

// 删除堆顶的数据,并且保持它继续是一个堆 O(logN)
void HeapPop(Heap* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	//堆向下调整
	AdjustDown(php->a, php->size, 0);
}

     3.8 堆顶元素数据

HPDataType HeapTop(Heap* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

     3.9 堆的数据个数

int HeapSize(Heap* php)
{
	assert(php);
	return php->size;
}

     3.10 堆的销毁

要释放我们建堆时,申请数组的空间,然后将其置为空。

void HeapDestory(Heap* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

     3.11 堆的判空

bool HeapEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}

  4、堆的应用

     4.1 堆排序

进行堆排序,首先就是要完成建堆,而堆的类型分为大堆小堆,这两种堆类型对应着不同排序结构。

建堆:

  1. 升序:建大堆
  2. 降序:建小堆

利用堆删除思想来进行排序,建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

思路:(1)在这建的是大堆,让父亲节点大于孩子节点;

           (2)交换根结点与最后一个孩子结点,那么此时最大的结点就来到了堆的最后一位,将堆的元素个数减一,然后在从根结点(刚交换上去的结点)完成向下调整算法。(堆元素个数减一并不是将其删除,只是将它放到数组最后一个位置,然后除去最后一个元素,将剩下的元素继续进行堆排序)。

           (3)直到最后两个结点将其完成交换即可完成堆排序。

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			++child;
		}
		//(大堆)
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//堆排序 --- O(N*logN)
void HeapSort(int* a, int n)
{
	//向下调整建堆--- O(N) --- 好一点
	//升序:建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

     4.2 TOP-K 问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能 数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

1、用数据集合中前K个元素来建堆

  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆

2、用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

下面来一个实例,在一组10个数字中,找出前三大的数据。(建小堆)

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(HPDataType* a, int n, int parent)//n为数组的大小
{
	int child = parent * 2 + 1;//左孩子
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapCreate(Heap* php, HPDataType* a, int n)
{
	assert(php);
	//扩容
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);
	php->size = php->capacity = n;
	//先建小堆(3个元素)
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(php->a, n, i);
	}
	//再将剩余7个元素与根结点比较插入
	for (int i = n; i < 10; i++)
	{
		//取前三大元素,建小堆,大于堆顶元素进行交换,判断,调整
		if (a[i] > php->a[0])
		{
			Swap(&a[i], &php->a[0]);
			AdjustDown(php->a, 3, 0);
		}
	}
}
void Test()
{
	int arr[10] = { 6,8,5,2,9,7,4,0,1,3 };
	Heap hp;
	HeapCreate(&hp, arr, 3);
	for (int i = 0; i < 3; i++)
	{
		printf("%d ", hp.array[i]);
	}
	printf("\n");
}

 


 

本文要是有不足的地方,欢迎大家在下面评论,我会在第一时间更正。

 老铁们,记着点赞加关注!!!  

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

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

相关文章

OMG--RTPS(Real Time Publish Subscribe Protocol)

OMG--RTPS&#xff08;Real Time Publish Subscribe Protocol&#xff09; 1 概述2 内容缩写DDS 有线协议的要求RTPS 有线协议The RTPS Platform Independent Model (PIM)The Structure ModuleThe Messages ModuleThe Behavior ModuleThe Discovery Module The RTPS Platform S…

Xuperchain多节点网络搭建+加节点+测试

环境准备 创建网络部署环境 # 在xuperchain目录执行 make testnet 种子节点 # 查看node1节点连接地址netURL cd node1 ./bin/xchain-cli netURL preview # 得到如下结果,实际使用时,需要将ip配置节点的真实ip,port配置成 /ip4/{{ip}}/tcp/{{port}}/p2p/Qmf2HeHe4sspGkfR…

深度学习应用篇-计算机视觉-OCR光学字符识别[7]:OCR综述、常用CRNN识别方法、DBNet、CTPN检测方法等、评估指标、应用场景

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

上课补充的知识

题目 char类型的默认值是\u0000 数组的创建方式 数组的遍历 遍历:从头到尾,依次访问数组每一个位置,获取每一个位置的元素.形式如下: 我们通过数组的下标操作数组,所以for循环变量操作的也是数组下标 开始:开始下标0 结束:结束下标length-1 如何变化: 语法&#xff1a; for…

大学结束啦!!!

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

神舟笔记本“性能、娱乐、省电、安静”模式之间的区别

前言&#xff1a;主要是对比神舟笔记本电脑“性能、娱乐、省电、安静”模式之间的区别 工具及硬件 名称版本号电脑Z8D6 2.5k屏鲁大师6.1023.xxx 之所以使用鲁大师&#xff0c;主要是为了节省时间.另外仅仅只是为了做横向对比&#xff0c;不需要太专业的工具。 实验中有两个变…

六级备考6天|CET-6|听力第一二三四讲|复习回顾|长对话篇章|14:00~16:30

长对话 篇章 目录 听写笔记 练习讲义 听写笔记 1. 听力策略 听前&#xff1a;读题——分析文章——预测题目 听中&#xff1a;划出听到的内容——对应程度高为正确选项 听后&#xff1a;不听题目——往下读题 2. 重点词汇 proofread / ˈpruːfriːd / …

CodeWhisperer插件使用体验

官方教程点击跳转 使用工具 1.vscode 2.插件(AWS Toolkit),免费使用 安装以后如何使用 1.首先要有一个aws账号 2.插件下载好以后登录aws账号&#xff0c;我们主要用这款插件的CodeWhisperer这个功能&#xff0c;其它的自行看官方教程了解。 注意事项&#xff1a;我们在从vs…

杭州互联网医疗Java实习一面

目录 1.java集合知道哪些2.ArrayList和LinkedList插入效率对比3.HashMap的底层结构4.HashMap怎么实现线程安全4.介绍下reentrantlock5.Redis分布式锁的实现原理7.知道哪些排序算法8.快排的原理9.Spring的AOP作用和原理10.MySQL的InnoDB索引结构11.网络中TCP和UDP的区别12.JVM的…

delphi 调用youtube-dl命令,下载youtube视频,原理及源代码

一、概要 1、Youtube-dl工具 强大的视频下载命令行工具Youtube-dl项目由Ricardo Garcia创建于2008年&#xff0c;源代码由Python编写&#xff0c;托管在GitHub上&#xff0c; 最初仅支持YouTube&#xff0c;但随着项目的发展&#xff0c;也开始支持其他视频网站&#xff0c;优势…

如何优化selenium webdriver的执行速度

目录 前言 在page_source中断言text比直接使用text属性断言要快 元素越具体&#xff0c;获取text的速度越快 使用变量去缓存没有变化的元素 快速在文本框中输入大文本 使用动态等待进行动态/AJAX 操作而不是固定睡眠 最后 前言 让自动化测试脚本正常工作只是自动化测试的…

微信小程序的自动化测试框架Minium详解,10分钟掌握

目录 前言 minium 是为小程序专门开发的自动化框架 文档使用 框架依赖运行环境部署 使用 打开工具 特别说明&#xff1a; 总结&#xff1a; 前言 微信发布了小程序的自动化测试框架Minium&#xff0c;提供了多种运行验证方式&#xff0c;其特点&#xff1a; 支持一套脚…

Alloy Tutorial(2)LastPass; cacheMemory

文章目录 LastPass整体 solution 代码&#xff1a; cacheMemory LastPass module LastPass/** LastPass password map** A simple example to explain basics of Alloy. ** The PassBook keeps track of a set of users passwords for a set of URLs. * For each User/URL pai…

【阿里云】第一次进行域名注册、备案以及使用全过程

前言 随着ChatGPT的爆火&#xff0c;让我直面感受到了一项技术的突破可以产生堪比原子弹爆炸的威力&#xff0c;因而在品尝过ChatGPT带来的便利与甜头后&#xff0c;就一直在跟进&#xff0c;同时也在能力范围内&#xff0c;让数十位朋友使用上了ChatGPT 前段时间&#xff0c…

ftrace学习 —— user_events的用法

参考 https://docs.kernel.org/trace/user_events.html 测试程序 samples/user_events/example.c tools/testing/selftests/user_events/ftrace_test.c 正文 通过user_event可以实现对应用程序的跟踪&#xff0c;类似linux内核中的tracepoint那样。相似的方法还有借助/sys…

走进docker

一、Docker 概述 1、Docker的概念 • Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源 • Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机” • Docker 的容器技术可以在一台主机上轻松为任何应用创建一…

异常数据检测 | Python实现基于高斯概率分布的异常数据检测

文章目录 文章概述模型描述源码分享学习小结参考资料文章概述 高斯分布也称为正态分布。它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。 模型描述…

asp.net审计项目管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net审计项目管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 二、功能介绍 (1)科室管理&…

GIT远程仓库(随笔)

目录 前言 一、GIt常见命令 二、概念原理 三、常见的代码托管平台 四、配置SSH公钥 五、操作 1、注册账号 2、在gitee中&#xff0c;创建远程仓库 3、Git命令创建本地仓库 4、Git命令创建第一个版本提交 5、Git命令添加远程仓库 6、推送 7、修改开源项目 ​编辑 8、…

浅谈数据库系统:MySQL的简介与安装配置

前言 ✨文末送书&#xff0c;小K赠书活动第一期 目录 前言一、数据库系统概述数据(Data)数据库(Database)数据库管理系统(Database Management System,DBMS)数据库系统(Database System,DBS)什么是SQL 二、MySQL的简介与安装MySQL简介MySQL下载与安装下载解压版安装配置安装版安…