数据结构与算法:二叉树之“堆排序”

news2024/12/26 22:09:27

目录

一、树概念及结构

二、二叉树树概念及结构

 特殊的二叉树

三、堆的概念及结构

四、堆的创建

1、声明结构体

2、初始化 

3、销毁

4、添加新元素

5、交换元素 

6、向上调整

7、判断堆是否为空

8、移除堆顶元素

9、向下调整

10、获取堆元素个数 

五、使用堆排序

 排降序建小堆

 完整版:

Heap.h声明部分

Heap.c函数部分

text.c使用及测试部分


一、树概念及结构

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
  • 有一个特殊的结点,称为根结点,根节点没有前驱结点。
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1 <= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继。
  • 因此,树是递归定义
  • 注意:树形结构中,子树之间不能有交集,否则就不是树形结构

  • 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6
  • 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点
  • 非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G...等节点为分支节点
  • 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
  • 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
  • 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  • 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
  • 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
  • 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
  • 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
  • 森林:由m(m>0)棵互不相交的树的集合称为森林;

二、二叉树树概念及结构

二叉树是一个由n(n>=0)个结点构成的有限集合,其中该集合可以为空,这时称其为空二叉树;或者由一个根结点以及两个互不相交的左子树和右子树组成,且左右子树均为二叉树。在二叉树中,子树被明确区分为左子树和右子树,且它们的顺序不可颠倒。

  • 值得注意的是,二叉树的定义具有递归性质,因为二叉树本身可以为空,根结点可以有空的左子树或空的右子树。
  • 这使得二叉树与普通树有明显的区别,即使只有一棵子树存在,也需要明确指定它是左子树还是右子树。这是二叉树与树最主要的区别之一。
  • 请注意,二叉树不同于一般的树,因为它的子树具有左右之分,并且顺序不能颠倒。因此,“二叉树是结点度为2的树”的说法是不正确的。

二叉树的基本形态包括以下五种:

 特殊的二叉树

当涉及到二叉树的特殊类型时,有两个主要概念需要了解:满二叉树和完全二叉树。

  • 满二叉树满二叉树是一种特殊的二叉树,其特点是每个层级的结点数都达到最大值。具体来说,如果一个二叉树的深度为K,且结点总数为2^K - 1,那么它就是一个满二叉树。满二叉树的每一层都包含最大数量的结点,使得它具有很特殊的结构。
  • 完全二叉树完全二叉树是一种高效的数据结构,与满二叉树相关。一个二叉树如果在深度为K的情况下,其结点都与深度为K的满二叉树中的编号从1到n的结点一一对应,那么它就被称为完全二叉树。需要注意的是,满二叉树是完全二叉树的一个特殊情况。
性质
  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^{i-1}个结点。
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^{h}-1
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 n0 , 度为2的分支结点个数为 n2 ,则有 n0 =n2 +1。
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度h=log以2为底,n+1的对数。
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
  • 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  • 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  • 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

 

三、堆的概念及结构

堆(Heap)是一种特殊的树状数据结构,通常用于实现优先队列和对数据进行排序。堆的主要特点是它是一棵树,其中每个节点的值满足特定的堆属性。在堆中,通常有两种主要类型:最大堆和最小堆。

  • 最大堆(Max Heap):在最大堆中,每个节点的值都不小于其子节点的值,即根节点的值最大。这意味着最大堆的最大元素总是位于根节点,而子树中的值递减。

  • 最小堆(Min Heap):在最小堆中,每个节点的值都不大于其子节点的值,即根节点的值最小。这意味着最小堆的最小元素总是位于根节点,而子树中的值递增。

堆的常见用途包括:

  • 优先队列:堆可以用来实现高效的优先队列,使得可以快速访问和删除具有最高或最低优先级的元素。

  • 堆排序:堆排序是一种高效的排序算法,它利用堆的性质来进行排序。它的时间复杂度为O(n log n)。

堆通常是以数组的形式来表示,其中父节点和子节点之间的关系通过数组索引来建立。具体来说,对于一个具有n个元素的堆,节点的索引从1到n编号,其中:

  • 父节点的索引为i,则它的左子节点的索引为2i,右子节点的索引为2i + 1。
  • 子节点的索引为i,则其父节点的索引为i/2。

这种数组表示方法使得堆的操作更加高效,因为它不需要使用额外的指针来表示树的结构。

四、堆的创建

本次以小堆举例进行讲解 

1、声明结构体

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;
  • HPDataType 被定义为 int 类型,表示堆中存储的数据类型。
  • 创建堆的结构体Heap,定义别名为HP。
  • 指针a指向堆的数组
  • size为堆的当前大小
  • capacity为堆的容量

2、初始化 

void HeapInit(HP* php)
{
    assert(php);
    php->a = NULL;
    php->size = 0;
    php->capacity = 0;
}
  • assert 判断指针是否合法。
  • 指向数组的指针 a 初始化为 NULL。
  • size 和 capacity 初始化为0。

3、销毁

void HeapDestroy(HP* php)
{
    assert(php);
    free(php->a);
    php->a = NULL;
    php->capacity = php->size = 0;
}
  • assert 判断指针是否合法。
  • 释放数组空间,将 a 指针置空,同时将 capacity 和 size 设置为0。

4、添加新元素

void HeapPush(HP* 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, newCapacity * sizeof(HPDataType));
		if (tmp==NULL) {
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}
  • assert 判断指针是否合法。
  • 判断当前是否需要扩容,初始堆的容量为0,则为堆开辟四个HPDataType类型大小的空间,如果当前堆的大小size等于容量capacity,则将堆扩容为两倍原来大小的空间。
  • 扩容失败,打印错误信息,结束函数
  • 将扩容的空间赋值给指针a,更新容量capacity的大小。
  • 将要增加的元素插入数组a中,更新size大小。
  • 每次在堆中添加新元素时,小堆可能会被破坏,所以我们再添加新元素后,要在AdjustUp函数中判断是否需要进行向上调整

5、交换元素 

后续函数会经常用到,同一串代码放到函数里供其使用者调用比较好。 

void Swap(HPDataType* p1, HPDataType* p2)
{
    HPDataType tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

6、向上调整

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;
        }
    }
}
  • 首先通过当前的孩子节点child找到父节点parent。
  • 当child大于0时,进行判断当前chilid是否需要调整
  • 如果child位置元素小于parent位置元素,则通过Swap进行交换,然后新的孩子节点更新为parent位置,通过孩子节点更新新的父节点位置,然后继续比较和交换,直到不再需要交换为止。
  • 如果当前孩子节点不小于当前的父节点,则结束循环,当前节点不需要向上调整。

7、判断堆是否为空

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

8、移除堆顶元素

 一般来说,堆的移除操作通常是移除堆顶元素,这样大堆小堆的性质保持不变,如果移除堆底会破坏堆的性质。

void HeapPop(HP* php)
{
    assert(php);
    assert(!HeapEmpty(php));

    Swap(&php->a[0], &php->a[php->size - 1]);
    php->size--;
    AdjustDown(php->a, php->size, 0);
}
  • assert 判断指针是否合法。
  • 检查堆是否为空,为空则报错。
  • 移除堆顶元素有两种方法,首选第二种方法,不需要重新建堆,节约时间。
  • 首先交换堆顶堆尾,然后size减一完成删除,后续不会访问删除位置的元素,所以不释放内存空间也可以。
  • 然后进行向下调整。

9、向下调整

向下调整是从第一个节点(父节点)开始向下调整,传入参数命名为parent 

void AdjustDown(HPDataType* a, int size, int parent)
{
    int child = parent * 2 + 1;
    while (child < size) {
        if (child + 1 < size && a[child + 1] < a[child]) {
            child++;
        }
        if (a[child] < a[parent]) {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 - 1;
        }
        else {
            break;
        }
    }
}
  • 通过传入参数获取到当前的左子节点的位置。
  • 当child位置小于数组元素个数时进行判断。
  • 进入循环,首先判断检查右子节点是否存在并且比左子节点的值小,如果是,将 child 更新为右子节点的索引,以确保选择更小的子节点进行比较。
  • 比较选定的子节点的值与父节点的值,如果子节点的值小于父节点的值,就交换它们。
  • 更新parent为新的子节点位置,更新child为新的左子节点位置,然后继续比较和交换,直到不再需要交换为止。
  • 如果当前子节点不小于当前父节点则停止循环。

10、获取堆元素个数 

int HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

五、使用堆排序

void HeapSort(int* a, int n)
{
	HP hp;
	HeapInit(&hp);
    // 时间复杂度:N*logN
	for (int i = 0; i < n; ++i)
	{
		HeapPush(&hp, a[i]);
	}

	// 时间复杂度:N*logN
	int i = 0;
	while (!HeapEmpty(&hp))
	{
		int top = HeapTop(&hp);
		a[i++] = top;
		HeapPop(&hp);
	}

	HeapDestroy(&hp);
}

可以使用这种方式,但有诸多弊端: 

  1. 要先有一个堆,太麻烦。
  2. 空间复杂度+拷贝数据

 排降序建小堆

所以我们要在传入的原数组上排降序,需要使用建小堆的方式向上调整。

void HeapSort(int* a, int n)
{
	// 建堆--向上调整建堆
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);

		// 再调整,选出次小的数
		AdjustDown(a, end, 0);

		--end;
	}
}
  • 从根节点的子节点开始向上建堆,除了根节点以外,每个节点都进行向上调整。
  • 定义堆的最后一个节点end为n-1
  • 我们将堆的根节点(也就是最小值)与堆的最后一个元素交换,即将最小值放到排序尾部即为好的部分。接下来,通过调用AdjustDown函数,将堆的大小减一,再次将堆调整为最小堆。
  • 重复while循环内部操作,直到整个数组排序完成。每次交换和堆的调整都会将最小的元素添加到已排序的部分,直到整个数组都有序。

HeapSort的时间复杂度为O(nlog(n)),它不需要额外的空间来存储数据,所以是一种原地排序算法。它在最坏情况下的性能仍然是O(nlog(n)),因此相对稳定,适用于大规模数据的排序。 

我们也可以向下建堆:

倒着调整叶子节点不需要处理,从倒树第一个非叶子节点开始,即最后一个节点的父节点开始调整。

void HeapSort(int* a, int 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;
	}
}

 完整版:

Heap.h声明部分

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

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

void HeapInit(HP* php);
void HeapDestroy(HP* php);

void AdjustUp(HPDataType* a, int child);
void HeapPush(HP* php, HPDataType x);
bool HeapEmpty(HP* php);
void AdjustDown(int* a, int n, int parent);
void HeapPop(HP* php);

HPDataType HeapTop(HP* php);
int HeapSize(HP* php);

Heap.c函数部分

#include "Heap.h"

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

void HeapDestroy(HP* php)
{
	assert(php);

	free(php->a);
	php->a = NULL;
	php->capacity = php->size = 0;
}

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;
		}
	}
}

void HeapPush(HP* 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, newCapacity * sizeof(HPDataType));
		if (tmp==NULL) {
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size==0;
}
void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size) {
		if (child + 1 < size && 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 HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));

	return php->a[0];
}

int HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

text.c使用及测试部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"

void HeapSort(int* a, int n)
{
	// 建堆--向上调整建堆
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}

    // 建堆--向下调整建堆
	//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;
	}		
}

int main()
{
	int a[] = { 7,8,3,5,1,9,5,4 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < 8; i++) {
		printf("%d  ", a[i]);
	}
	return 0;
}

//---测试堆函数功能---
//int main()
//{
//	HP hp;
//	HeapInit(&hp);
//	int a[] = { 65,100,70,32,50,60 };
//	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
//	{
//		HeapPush(&hp, a[i]);
//	}
//	
//	while (!HeapEmpty(&hp))
//	{
//		int top = HeapTop(&hp);
//		printf("%d\n", top);
//		HeapPop(&hp);
//	}
//
//	return 0;
//}

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

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

相关文章

【网络编程】传输层——UDP协议

文章目录 一、传输层1. 再谈端口号2. 端口号范围划分3. 认识知名端口号4. 两个问题5. netstat 与 pidof 二、UDP协议1. UDP协议格式2. UDP协议的特点3. 面向数据报4. UDP的缓冲区5. UDP使用注意事项6. 基于UDP的应用层协议 一、传输层 传输层 负责负责两台计算机之间的端到端的…

阿里云2023年双11活动时间、活动入口、活动内容详细解读

阿里云2023年双11活动正在火热进行中&#xff0c;双11活动时间&#xff0c;阿里云推出了金秋上云季活动&#xff0c;活动包括满减礼包福利&#xff0c;云产品降价让利&#xff0c;下面给大家整理分享阿里云双11活动时间、活动入口、活动内容&#xff0c;助力大家轻松上云&#…

网络爬虫-Requests库主要方法解析

一、Requests库的7个主要方法 其中&#xff0c;request()是 基础方法&#xff0c;其他6个方法都是基于request()的&#xff0c;但最常用的是get() 和 head() 二、request() 13个访问控制参数&#xff1a; 三、get(): 获取某一个url链接的相关资源 四、head() 五、post() 六、…

LCR 021. 删除链表的倒数第 N 个结点

这篇也是凑数的 .... 描述 : 给定一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点 题目 : LeetCode 删除链表的倒数第Nge节点 : LCR 021. 删除链表的倒数第 N 个结点 分析 : 首先创建一个虚拟节点(哨兵节点) , 虚拟节点下一节点指向头节…

从 malloc 分配大块内存失败 来简看 linux 内存管理

文章目录 背景Glibc MallocMalloc 分配大块内存失败原因Overcommit_memory 实现OOM (Out Of Memory) 的实现 背景 应用进程 malloc 返回了null&#xff0c;但是观察到的os 的free内存还有较大的余量 &#xff0c;很奇怪为什么会这样&#xff1f; 不可能是oom导致的&#xff0…

GAMP源码阅读(上)主要类型、后处理流程、RINEX文件读取

原始 Markdown文档、Visio流程图、XMind思维导图见&#xff1a;https://github.com/LiZhengXiao99/Navigation-Learning 文章目录 一、GAMP 简介1、程序概述2、工具箱介绍3、函数调用关系4、程序执行流程 二、基础类型定义1、宏定义2、结构体定义3、矩阵、向量、最小二乘、卡尔…

以“信”数智,筑“广”生态:亚信科技CEO高念书受邀出席中国广电数字化赋能大会

6月30日&#xff0c;由国家广播电视总局指导、中国广电集团主办的中国广电数字化赋能大会在京召开。国家广播电视总局党组成员、副局长杨小伟&#xff0c;工信部总工程师赵志国&#xff0c;中国移动党组成员、副总经理高同庆等出席会议并致辞&#xff0c;中广电移动网络有限公司…

【ICCV2023】频率成分在少样本学习中的重要性

论文标题&#xff1a;Frequency Guidance Matters in Few-Shot Learning 论文链接&#xff1a;https://openaccess.thecvf.com/content/ICCV2023/html/Cheng_Frequency_Guidance_Matters_in_Few-Shot_Learning_ICCV_2023_paper.html 代码&#xff1a;暂未开源 引用&#xff1a;…

基于SpringBoot的医院后台管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 患者管理 公告信息管理 公告类型管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 四、结论 前言 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理…

[云原生1.] Docker镜像的创建

文章目录 1. Docker镜像概述1.1 简介1.2 镜像结构的分层详解 2. 创建Docker镜像的方法类别2.1 基于已有镜像创建2.1.1 创建流程2.1.2 示例 2.2 基于本地模板创建2.2.1 示例 2.3 基于Dockerfile 创建 3. 联合文件系统&#xff08;UnionFS&#xff09;2.1 简介2.2 特性 4. Docker…

云原生-AWS EC2使用、安全性及国内厂商对比

目录 什么是EC2启动一个EC2实例连接一个实例控制台ssh Security groups规则默认安全组与自定义安全组 安全性操作系统安全密钥泄漏部署应用安全元数据造成SSRF漏洞出现时敏感信息泄漏网络设置错误 厂商对比参考 本文通过实操&#xff0c;介绍了EC2的基本使用&#xff0c;并在功…

【排序算法】 归并排序详解!分治思想!

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; 算法—排序篇 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言&#x1f324;️归并排序的思想☁️基本思想☁️归并的思想实现☁️分治法 &#x1f3…

并发编程 -常用并发设计模式

1. 优雅终止线程的设计模式 思考&#xff1a;在一个线程 T1 中如何优雅的终止线程 T2&#xff1f; 错误思路1&#xff1a;使用线程对象的 stop() 方法停止线程 stop 方法会真正杀死线程&#xff0c;如果这时线程锁住了共享资源&#xff0c;那么当它被杀死后就再也没有机会释 …

C/C++角谷猜想 2020年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C角谷猜想 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C角谷猜想 2020年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 所谓角谷猜想&#xff0c;是指对于任意一个正整数&…

windows电脑安装系统后固态硬盘和机械硬盘的盘符号顺序显示错乱,解决方法

一、场景 由于电脑磁盘是SSD固态硬盘自己拓展的1T机械硬盘组成&#xff0c;固态硬盘分为C、D两个盘区&#xff0c;机械硬盘分为E、F两个盘区。为了提升运行速度&#xff0c;系统安装在C盘&#xff0c;安装完成后按照习惯盘区顺应该为C、D、E、F&#xff0c;但实际情况却是D、E…

剑指offer --- 二维数组中的元素查找

目录 一、读懂题目 二、思路分析 三、代码呈现 总结 一、读懂题目 题目&#xff1a; 在一个二维数组中&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个函数&#xff0c;输入这样的个二维数组和一个整数&#…

用baostock库获取沪深300成分股

先看效果&#xff1a; 代码&#xff0c;bs_get_hs300.py import baostock as bs import pandas as pd# 登陆系统 lg bs.login() # 显示登陆返回信息 print(login respond error_code:lg.error_code) print(login respond error_msg:lg.error_msg)# 获取沪深300成分股 rs bs…

Android开发工具介绍(adb、AVD、DDMS)

目录 1. adb 1.1 查看设备 1.2 安装软件 1.3 卸载软件 1.4 登录设备 shell 1.5 从计算机上发送文件到目标机 1.6 从目标机上下载文件到计算机 1.7 显示帮助信息 2. AVD 2.1 AVD 的创建 2.2 启动 AVD 模拟器 3. DDMS 3.1 DDMS的启动方法 3.2 DDMS 工…

H5游戏源码分享-密室逃脱小游戏(考验反应能力)

H5游戏源码分享-密室逃脱小游戏&#xff08;考验反应能力&#xff09; 预判安全位置&#xff0c;这个需要快速的反应能力 源码 <!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /&…

WEB登录设备控制台异常——TLS协议问题

问题描述&#xff1a;登录设备web控制台浏览器报错&#xff0c;切换其他浏览器也有问题。 出现这个问题&#xff0c;大概率是网站支持的TLS协议很低&#xff0c;而浏览器的TLS协议很高&#xff0c;那么就是是降浏览器的TLS版本。 解决步骤&#xff1a; 1、火狐浏览器地址栏输…