【数据结构】05树

    • 1.2 结点的分类
    • 1.3 结点间的关系
    • 1.4 树的其他概念
    • 1.5 树的性质
  • 2. 二叉树
    • 2.1 满二叉树
    • 2.2 完全二叉树
    • 2.3 二叉排序树(二叉查找树)
  • 3. 二叉树的存储结构
    • 3.1 二叉树顺序存储结构
    • 3.2 二叉树的链式存储结构
  • 4. 二叉树的遍历
    • 4.1 层次遍历
    • 4.1 前序遍历
    • 4.2 中序遍历
    • 4.3 后序遍历
  • 5. 线索二叉树
    • 5.1 线索二叉树的数据结构
    • 5.2 线索二叉树求前驱和后继
  • 6. 二叉排序树
    • 6.1 二叉排序树的插入
    • 6.2 创建二叉排序树
    • 6.3 二叉排序树的查找
    • 6.4 二叉排序树的遍历
    • 6.5 删除二叉排序树的结点
    • 6.6 二叉排序树的查找效率
    • 6.7 完整实现
  • 7. 哈夫曼树(最优二叉树)
    • 7.1 构造哈夫曼树
    • 7.2 哈夫曼编码

树(Tree)是 n ( n ≥ 0 ) n(n\ge0) n(n0)个结点的有限集。 n = 0 n=0 n=0时称为空树。在任意一颗非空树中:①有且仅有一个特定的称为根(Root)的结点②当 n > 1 n>1 n>1时,其余结点可分为 m m m( m > 0 m>0 m>0)个互不相交的有限集 T 1 、 T 2 、 . . . 、 T m T_1、T_2、...、T_m T1T2...Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。如图中所示
在这里插入图片描述
子树 T 1 T_1 T1 T 2 T_2 T2是根结点A的子树。当然DGHI组成的树,又是以B为根结点的子树,EJ是以C为根结点的子树。

注意: 1. n>0时,树的根结点是唯一的,不可能存在多个根结点。 2. m>0时,子树的个数没有限制,但它们一定是互不相交的。

1.2 结点的分类

树的结点包含一个数据元素及其若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支节点。除根结点之外,分支节点也称为内部节点。树的度是树内各结点的度的最大值(不是和)。如下图中所示,这棵树的度是3。
在这里插入图片描述

1.3 结点间的关系

结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)结点。同一个双亲的孩子之间称为兄弟(Sibling)结点。结点的祖先是从根到该结点所经分支上的所有结点。对于图中所示的树来说。B是A的Child,A是B的Parent,B和C是Sibling。对H来说,GIJ都是它的Sibling,D是他的Parent,ABD都是它的祖先。

1.4 树的其他概念

结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。树中结点的最大层次称为树的深度(Depth)或高度,上面图中所示的树的深度为4。

1.5 树的性质

  1. 树中的结点总数等于所有结点的度加一(对于上图:(2+1+2+3+1)+1 =10 个结点)
  2. m叉树中第 i , i ≥ 1 i,i\ge1 i,i1层上至多可以有 m i − 1 m^{i-1} mi1个结点。

2. 二叉树

二叉树(Binary Tree)是树形结构中最重要的类型,它的规律性强,应用广泛。
二叉树的每个结点最多只能拥有两棵子树,分别称为左子树和右子树。二叉树可以有五种基本形态:

  • 空树
  • 只有根结点
  • 只有左子树
  • 只有右子树
  • 左右子树都有

2.1 满二叉树

一颗高度为h,且含有 2 h − 1 2^{h}-1 2h1个结点的二叉树称为满二叉树。
对于编号为i的结点,左子结点编号为2i,右结点编号为2i+1,双亲结点为 ⌊ \lfloor i/2 ⌋ \rfloor (向下取整)。

2.2 完全二叉树

一颗高度为h,有n个结点的完全二叉树,它的每个结点都与高度相同的满二叉树中的结点编号一一对应。(完全二叉树除了最后一层,其他的都是满的)。如果最后一层中有度为1的结点,那么它的子结点一定是左节点。
性质:

  • 对于编号为i的结点,左子节点为2i,右结点为2i+1,双亲结点为 ⌊ \lfloor i/2 ⌋ \rfloor
  • 若结点编号i ≤ \le ⌊ \lfloor n/2 ⌋ \rfloor ,则结点为分支结点,否则为叶结点。
  • 如果编号为i的结点为叶结点或只有左孩子,则编号大于i的结点均为叶结点。

2.3 二叉排序树(二叉查找树)

树上任意结点,如果存在左子树和右子树,则左子树上所有结点元素值都小于该结点,右子树上所有结点元素值都大于该结点。

3. 二叉树的存储结构

3.1 二叉树顺序存储结构

二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置,也就是数组的下标能够体现结点之间的逻辑关系。
完全二叉树:编号为i的结点,左子节点为2i,右子节点为2i+1,双亲结点 ⌊ \lfloor i/2 ⌋ \rfloor
体现在数组中下表为i的结点,左子节点下标为2i+1,右子节点下标为2i+2,双亲结点下标为 ⌊ \lfloor (i-1)/2 ⌋ \rfloor
在这里插入图片描述
普通二叉树:补齐成为完全二叉树,按照完全二叉树存放,数组中利用特殊值来填充。但利用顺序存储的方法存储普通二叉树,补齐成为完全二叉树再存储,容易造成空间的浪费,比较适合顺序存储结构。

3.2 二叉树的链式存储结构

struct BiTNode{TElemType data;//数据域struct BiTNode *lchild,*rchild;//左右孩子结点指针struct BiTNode *parent; // 指向双亲结点指针
}BiTNode;
typedef BiNode* BiTree;

4. 二叉树的遍历

二叉树的遍历,是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。

4.1 层次遍历

规则:树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下的逐层遍历,同一层中,按从左到右的顺序对结点逐个访问。
方法:初始化将二叉树根结点插入队列中。开始,出队队头元素,并将队头元素的左右子结点入队(没有子结点入队为空),直到队列中为空。依次出队的元素就是层次遍历的顺序。
图示:
在这里插入图片描述
代码实现:

void LevelOrder(BiTree TT)
{std::queue<BiTreeNode*> qq; // 队列qq.push(TT); //根结点入队while (!qq.empty()){// 队头出队BiTreeNode* out = qq.front();qq.pop();cout << out->data << " ";if (out->lchild != nullptr) // 左子结点{qq.push(out->lchild);}if (out->rchild != nullptr) // 右子结点{qq.push(out->rchild);}}cout << endl;
}

4.1 前序遍历

规则:二叉树为空,则空操作返回,否则从根结点开始,先访问根结点,然后前序遍历左子树,再前序遍历右子树。
代码实现:

// 前序遍历
void PreOrder(BiTree TT)
{// 为空返回if (TT==nullptr){return;}// 访问根结点cout << TT->data << " ";// 访问左子树PreOrder(TT->lchild);// 访问右子树PreOrder(TT->rchild);
}

4.2 中序遍历

规则:二叉树为空,则空操作返回,否则从根结点开始,先中序遍历根结点的左子树,然后访问根结点,最后中序遍历右子树。
代码实现:

// 中序遍历
void MidOrder(BiTree TT)
{// 为空返回if (TT == nullptr){return;}MidOrder(TT->lchild);// 访问左子树cout << TT->data << " "; // 访问根结点MidOrder(TT->rchild); // 访问右子树
}

4.3 后序遍历

规则:二叉树为空,则空操作返回,否则从左到右,先叶子后结点的方式遍历访问左右子树,最后访问的是根结点。
代码实现:

// 后序遍历
void PostOrder(BiTree TT)
{if (TT == nullptr){return;}// 访问左子树PostOrder(TT->lchild);// 访问右子树PostOrder(TT->rchild);// 访问根结点cout << TT->data << " ";
}

5. 线索二叉树

把指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded Binary Tree) 。
二叉树线索化是将二叉链表中的空指针指向前驱或后继结点。而前驱或后继结点的信息只有遍历时才能得到,因此二叉树的线索化又分为先序线索二叉树、中序线索二叉树和后序线索二叉树。

  • 如果该结点没有左子结点(左子树),则将左指针指向遍历序列中它的前驱结点。
  • 如果该结点没有右子节点(右子树),则将右指针指向遍历序列中它的后继节点。

5.1 线索二叉树的数据结构

struct TBtNode
{ElemType data;TBtNode* lchild;TBtNode* rchild;bool ltag,rtage; // 左右指针的类型,0-非线索指针,1-线索指针
};
typedef TBtNode* TBtree;

5.2 线索二叉树求前驱和后继

先序线索二叉树:可求后继:

  • 如果当前结点的右指针存放的是线索,右指针指向的结点就是后继结点。
  • 如果当前结点的右指针存放的是结点,如果结点存在取左子结点,否则取右子结点。

后序线索二叉树:可求前驱:

  • 如果当前结点的左指针存放的是线索,左指针指向的结点就是前驱结点
  • 如果当前结点的左指针存放的是结点,如果结点存在取右子结点,否则取左子结点。

中序线索二叉树:可求前驱和后继:
求后继:

  • 如果当前结点右指针存放的是线索,右指针指向的结点就是后继节点
  • 如果当前结点右指针存放的是结点,右子树中序遍历的第一个结点即后继结点

求前驱

  • 如果当前结点左指针存放的是线索,左指针指向的结点就是后继结点
  • 如果当前结点左指针存放的是结点,左子树中序遍历的第一个结点即后继结点

6. 二叉排序树

二叉排序树(二叉搜索树,二叉查找树,Binary Sort Tree BST),一颗飞控的二叉排序树具有下列性质:

  1. 如果左子树不空,则左子树上所有结点的值都小于根结点值
  2. 如果右子树不空,则右子树上所有结点的值都大于根结点值
  3. 左右子树也分别是二叉排序树

左子树<根<右子树
数据结构

typedef int ElemType;struct BSTNode
{ElemType data; // 数据域BSTNode* lchild; // 左子结点BSTNode* rchild; // 右子结点
};typedef BSTNode* BSTree;

6.1 二叉排序树的插入

  • 从根结点开始,递归插入,小于当前结点的值,递归左子树,大于当前结点的值递归右子树。
  • 插入元素肯定是在叶结点或根结点
  • 如果插入元素重复,则返回异常
// 在二叉排序树中插入结点
bool InsertBST(BSTree& tree, ElemType* data)
{if ( tree== nullptr)  // 当树为空,创建根结点{tree = new BSTNode;memcpy(&(tree->data), data, sizeof(ElemType));tree->lchild = tree->rchild = nullptr;return true;}// 如果元素已存在返回if (*data == (tree)->data){return false;}// 插入if (*data < (tree)->data){return InsertBST((tree)->lchild, data); // 向左递归}else{return InsertBST((tree)->rchild, data); // 向右递归}
}

6.2 创建二叉排序树

  • 相同的序列创建的二叉排序树是唯一的
  • 同一集合创建的二叉排序树是不同的(根结点不同,从而二叉排序树不同)
  • 用二叉树的先序遍历创建的二叉排序树与原树相同
// 创建二叉排序树
void CreateBST(BSTree& tree, ElemType arr[], int len)
{tree = NULL;for (int i = 0; i < len; i++){InsertBST(tree, &arr[i]);}
}

6.3 二叉排序树的查找

根据带查找元素值与结点值的大小比较,小于结点值,递归左子树,大于结点值递归右子树。

// 在二叉排序树中查找结点
BSTNode* FindNode(BSTree tree, ElemType data)
{if (tree == nullptr) // 查找失败{return nullptr; }if (data == tree->data){return tree;}if (data < tree->data){return FindNode(tree->lchild, data); //向左递归}else{return FindNode(tree->rchild, data); //向右递归}
}

6.4 二叉排序树的遍历

利用中序遍历输出的二叉排序树是按照从小到大的顺序(先左子树(即先小的),然后根结点,最后右子树(最后大的))

// 中序遍历二叉排序树
void InOrder(BSTree* tree)
{if (*tree == nullptr){return;}// 先左子树InOrder(&((*tree)->lchild));// 根结点cout << (*tree)->data << " ";// 右子树InOrder(&((*tree)->rchild));
}

6.5 删除二叉排序树的结点

  • 如果树只有根结点,并且待删除的结点就是根结点
  • 如果待删除的结点是叶结点,直接删除,不会破坏二叉排序树的性质
  • 如果待删除的结点只有左子树或右子树,则让子树代替自己
  • 如果待删除的结点有左子树和右子树,让左子树最右侧的结点代替自己,然后删除左子树最右侧的结点。(也可以让右子树最左侧的结点代替自己,然后删除右子树最左侧的结点。)
bool DeleteNode(BSTree& tree, ElemType* data)
{if (tree == nullptr) // 树为空{return false;}// (1) 树只有根节点,并且待删除结点就是根结点if ((tree->lchild == nullptr && tree->rchild == nullptr) && *data == tree->data){// 删除根结点delete tree;tree = nullptr;return true;}// BSTNode* ptr = tree; // BSTNode* pre_ptr = nullptr; // 记录双亲结点int r_or_l = 0; // 记录结点是双亲结点的左子树还是右子树while (ptr != nullptr){if (ptr->data == *data) // 找到结点{break;}pre_ptr = ptr; // 记录双亲结点if (*data < ptr->data) // 向左递归 {ptr = ptr->lchild;r_or_l = 1;}else                   // 向右递归{ptr = ptr->rchild;r_or_l = 0;}}if (ptr == nullptr) // 未找到{return false;}// (2) 如果待删除的结点是叶结点,直接删除if (ptr->lchild == nullptr && ptr->rchild == nullptr){if (r_or_l == 0) // 当前结点是双亲结点的右子结点{pre_ptr->rchild = nullptr;}else  // 当前结点是双亲结点的左子结点{pre_ptr->lchild = nullptr;}delete ptr; // 删除当前结点ptr = nullptr;return true;}// (3) 如果待删除结点只有左子树或只有右子树if (ptr->lchild == nullptr || ptr->rchild == nullptr){if (ptr->lchild != nullptr) // 只有左子树{// 左子树取代当前结点// 双亲结点指向当前结点的左子树if (r_or_l == 0) // 当前结点的左子树,是双亲结点的右子树{pre_ptr->rchild = ptr->lchild;delete ptr; // 删除当前结点ptr = nullptr;}else  // 当前结点的左子树,是双亲结点的左子树{pre_ptr->lchild = ptr->lchild;delete ptr; // 删除当前结点ptr = nullptr;}}else // 只有右子树{// 右子树取代当前结点// 双亲结点指向当前结点的右子树if (r_or_l == 0) // 当前结点的右子树,是双亲结点的右子树{pre_ptr->rchild = ptr->rchild;delete ptr; // 删除当前结点ptr = nullptr;}else  // 当前结点的右子树,是双亲结点的左子树{pre_ptr->lchild = ptr->rchild;delete ptr; // 删除当前结点ptr = nullptr;}return true;}}// (4) 如果待删除结点已经有左子树和右子树,让左子树最右侧的结点取代自己,然后再删除左子树最右侧的结点BSTNode* tmp_ptr = ptr->lchild;BSTNode* pre_ptr2 = nullptr; // 记录最右侧结点的双亲结点位置while (tmp_ptr->rchild) // 找到当前结点的左子树最右侧结点{pre_ptr2 = tmp_ptr;tmp_ptr = tmp_ptr->rchild;}// 最右侧结点替代当前结点ptr->data = tmp_ptr->data;// 左子树最右侧结点必定没有右子树// 双亲结点右指针最右侧结点的左子树pre_ptr2->rchild = tmp_ptr->lchild; // 删除最右侧结点delete tmp_ptr;tmp_ptr = nullptr;return true;
}

6.6 二叉排序树的查找效率

在查找操作中,需要对比结点值的次数即查找长度,反映了查找运算的时间复杂度。
查找成功的平均查找长度(ASL ,Average Search Length)。ASL=∑(每层结点个数 X 该层层数)/结点个数
例如对二叉排序树
在这里插入图片描述
的ASL=(11+22+33+42)/8=2.75
在这里插入图片描述
查找失败的ASL=(21+34+4*4)/9=3.33
最好的情况:平均查找长度O(log2n)
最坏的情况:平均查找长度O(n)

6.7 完整实现

#include <iostream>
using namespace std;
typedef int ElemType;struct BSTNode
{ElemType data; // 数据域BSTNode* lchild; // 左子结点BSTNode* rchild; // 右子结点
};typedef BSTNode* BSTree;// 在二叉排序树中插入结点
bool InsertBST(BSTree& tree, ElemType* data)
{if ( tree== nullptr)  // 当树为空,创建根结点{tree = new BSTNode;memcpy(&(tree->data), data, sizeof(ElemType));tree->lchild = tree->rchild = nullptr;return true;}// 如果元素已存在返回if (*data == (tree)->data){return false;}// 插入if (*data < (tree)->data){return InsertBST((tree)->lchild, data); // 向左递归}else{return InsertBST((tree)->rchild, data); // 向右递归}
}// 创建二叉排序树
void CreateBST(BSTree& tree, ElemType arr[], int len)
{tree = NULL;for (int i = 0; i < len; i++){InsertBST(tree, &arr[i]);}
}// 在二叉排序树中查找结点
BSTNode* FindNode(BSTree tree, ElemType data)
{if (tree == nullptr) // 查找失败{return nullptr; }if (data == tree->data){return tree;}if (data < tree->data){return FindNode(tree->lchild, data); //向左递归}else{return FindNode(tree->rchild, data); //向右递归}
}// 删除二叉树结点
bool DeleteNode(BSTree& tree, ElemType* data)
{if (tree == nullptr) // 树为空{return false;}// (1) 树只有根节点,并且待删除结点就是根结点if ((tree->lchild == nullptr && tree->rchild == nullptr) && *data == tree->data){// 删除根结点delete tree;tree = nullptr;return true;}// BSTNode* ptr = tree; // BSTNode* pre_ptr = nullptr; // 记录双亲结点int r_or_l = 0; // 记录结点是双亲结点的左子树还是右子树while (ptr != nullptr){if (ptr->data == *data) // 找到结点{break;}pre_ptr = ptr; // 记录双亲结点if (*data < ptr->data) // 向左递归 {ptr = ptr->lchild;r_or_l = 1;}else                   // 向右递归{ptr = ptr->rchild;r_or_l = 0;}}if (ptr == nullptr) // 未找到{return false;}// (2) 如果待删除的结点是叶结点,直接删除if (ptr->lchild == nullptr && ptr->rchild == nullptr){if (r_or_l == 0) // 当前结点是双亲结点的右子结点{pre_ptr->rchild = nullptr;}else  // 当前结点是双亲结点的左子结点{pre_ptr->lchild = nullptr;}delete ptr; // 删除当前结点ptr = nullptr;return true;}// (3) 如果待删除结点只有左子树或只有右子树if (ptr->lchild == nullptr || ptr->rchild == nullptr){if (ptr->lchild != nullptr) // 只有左子树{// 左子树取代当前结点// 双亲结点指向当前结点的左子树if (r_or_l == 0) // 当前结点的左子树,是双亲结点的右子树{pre_ptr->rchild = ptr->lchild;delete ptr; // 删除当前结点ptr = nullptr;}else  // 当前结点的左子树,是双亲结点的左子树{pre_ptr->lchild = ptr->lchild;delete ptr; // 删除当前结点ptr = nullptr;}}else // 只有右子树{// 右子树取代当前结点// 双亲结点指向当前结点的右子树if (r_or_l == 0) // 当前结点的右子树,是双亲结点的右子树{pre_ptr->rchild = ptr->rchild;delete ptr; // 删除当前结点ptr = nullptr;}else  // 当前结点的右子树,是双亲结点的左子树{pre_ptr->lchild = ptr->rchild;delete ptr; // 删除当前结点ptr = nullptr;}return true;}}// (4) 如果待删除结点已经有左子树和右子树,让左子树最右侧的结点取代自己,然后再删除左子树最右侧的结点BSTNode* tmp_ptr = ptr->lchild;BSTNode* pre_ptr2 = nullptr; // 记录最右侧结点的双亲结点位置while (tmp_ptr->rchild) // 找到当前结点的左子树最右侧结点{pre_ptr2 = tmp_ptr;tmp_ptr = tmp_ptr->rchild;}// 最右侧结点替代当前结点ptr->data = tmp_ptr->data;// 左子树最右侧结点必定没有右子树// 双亲结点右指针最右侧结点的左子树pre_ptr2->rchild = tmp_ptr->lchild; // 删除最右侧结点delete tmp_ptr;tmp_ptr = nullptr;return true;
}// 先序遍历二叉排序树
void PreOrder(BSTree* tree)
{if (*tree == nullptr){return;}// 根结点cout << (*tree)->data << " ";// 左子树PreOrder(&((*tree)->lchild));// 右子树PreOrder(&((*tree)->rchild));
}// 中序遍历二叉排序树
void InOrder(BSTree* tree)
{if (*tree == nullptr){return;}// 先左子树InOrder(&((*tree)->lchild));// 根结点cout << (*tree)->data << " ";// 右子树InOrder(&((*tree)->rchild));
}// 后序遍历二叉排序树
void PostOrder(BSTree* tree)
{if (*tree == nullptr){return;}// 先左子树InOrder(&((*tree)->lchild));// 右子树InOrder(&((*tree)->rchild));// 根结点cout << (*tree)->data << " ";
}int main(void)
{BSTree tree;//ElemType arr[] = { 1,3,5,2,4,8,6,7 };////  1 //    3//   2  5//     4 8//      6//       7ElemType arr[] = { 50,30,20,40,32,31,38,35,39,34,36,37,33 };CreateBST(tree, arr, sizeof(arr) / sizeof(ElemType));PreOrder(&tree);cout << endl;InOrder(&tree);cout << endl;PostOrder(&tree);cout << endl;ElemType e = 38;DeleteNode(tree, &e);InOrder(&tree);cout << endl;return 0;
}

7. 哈夫曼树(最优二叉树)

结点的路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数称为路径长度。
结点的权:结点的数值有某种现实的含义(如重要性、两个点之间的距离等)
结点的带权路径长度:从树的根结点到该结点的路径长度与该结点上的权值的乘积
树的带权路径长度:为树中所有叶子结点的带权路径长度之和(WPL,Weight Path Length)
在这里插入图片描述
在含有n个带权结点的二叉树中,WPL最小的二叉树称为哈夫曼树(最优二叉树)。如同图中所示,第三棵树才是哈夫曼树。
哈夫曼树并不唯一:将第三棵树左右结点位置调换依然是一颗哈夫曼树

7.1 构造哈夫曼树

详细过程图解:
初始结点看作是只有单个结点的树
在这里插入图片描述
先挑两个根结点权值最小的树,构建一颗新的树,并新增一个结点,权值为两子树权值之和
在这里插入图片描述
继续挑选权值最小的树,构建新的树
在这里插入图片描述
继续挑选权值最小的树,构建新的树
在这里插入图片描述
继续挑选权值最小的树,构建新的树
在这里插入图片描述继续挑选权值最小的树,构建新的树
在这里插入图片描述
继续挑选权值最小的树,构建新的树在这里插入图片描述
继续挑选权值最小的树,构建新的树
在这里插入图片描述
最终
在这里插入图片描述1. 初始结点都会成为叶结点,叶结点的权值越大,离根结点越近。
2. 如果叶结点有n个,共合并n-1次,哈夫曼树的结点总数为2n-1
3. 哈夫曼树不存在度为1的结点
4. 哈夫曼树不唯一,只要WPL最小就行

7.2 哈夫曼编码

可变长度编码,任何一个字符的编码都不是另一个字符编码的前缀,这种编码称作前缀编码。
利用哈夫曼树来设计前缀编码,用0和1表示左子树和右子树。

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

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

相关文章

如何申请阿里云服务器学生优惠,入口在这呢!

阿里云学生服务器免费申请&#xff0c;之前是云翼计划学生服务器9元/月&#xff0c;现在是高校计划&#xff0c;学生服务器可以免费申请&#xff0c;先完成学生认证即可免费领取一台云服务器ECS&#xff0c;配置为2核2G、1M带宽、40G系统盘&#xff0c;在云服务器ECS实例过期之…

Elasticsearch初步了解学习记录

目录 前言 一、ElasticSearch是什么&#xff1f; 二、使用步骤&#xff08;python版&#xff09; 1.引入包 2.连接数据库 3.创建索引 4.写入数据 5.查询数据 三、相关工具介绍 1.ES浏览器插件 总结 前言 随着数据量的不断增加&#xff0c;传统的查询检索在速度上遇…

IO——文件IO

1.1 概念 又称为系统IO&#xff0c;是系统调用&#xff0c;是操作系统提供的函数接口。 posix中定义的一组用于输入输出的函数。 1.2 特点 (1)没有缓冲机制&#xff0c;效率较低 (2)围绕文件标识符操作&#xff0c;非负整数&#xff0c;依次分配 (3) 文件IO默认打开了三个文…

正则表达式:量词(三)

正则表达式中的量词有以下几种:1. *: 匹配前面的字符0次或多次。2. : 匹配前面的字符1次或多次。3.?: 匹配前面的字符0次或1次。4. {n}: 匹配前面的字符恰好n次。5. {n,}: 匹配前面的字符至少n次。6. {n,m}:匹配前面的字符至少n次&#xff0c;但不超过m次。 以下是使用Python的…

计算机网络 子网掩码与划分子网

一、实验要求与内容 1、需拓扑图和两个主机的IP配置截图。 2、设置网络A内的主机IP地址为“192.168.班内学号.2”&#xff0c;子网掩码为“255.255.255.128”&#xff0c;网关为“192.168.班内学号.1”&#xff1b;设置网络B内的主机IP地址为“192.168.班内学号100.2”&#…

@AutoConfigurationPackage 和 @ComponentScan 有何区别?

首先&#xff0c;从名字上看&#xff0c;这两个注解意义特别接近&#xff0c;AutoConfigurationPackage 就是自动配置包&#xff0c;自动配置包的目的是能让系统扫描到包内的 Bean&#xff1b;ComponentScan 则是组件扫描&#xff0c;这个松哥在之前的教程中也多次提到过了&…

VBA 实现outlook 当邮件设置category: red 即触发自动创建jira issue

1. 打开: Outlook VBA&#xff08;Visual Basic for Applications&#xff09; 方法一: 在邮件直接搜索:Visual Basic editor 方法二: File -> Options -> Customize Ribbon-> 打钩 如下图: 2.设置运行VBA 脚本: File -> Options -> Trust center -> Trus…

Day37|贪心算法part06:738.单调递增的数字、968. 监控二叉树、贪心总结

738. 单调递增的数字 总体思想就是从后往前遍历&#xff0c;比较第i位和第i1位的大小&#xff0c;不符合顺序char[i]减1&#xff0c;i1位填9&#xff0c;找到需要填9的最先位置&#xff0c;然后填9。 class Solution {public int monotoneIncreasingDigits(int n) {String s …

win 安装 Stable Diffusion

注&#xff1a;本人使用的是 RTX2060 - 6G版 特别提醒&#xff1a;安装一定要 CUDA 和 PyTorch 版本能配套用&#xff0c;不然会有生成保存问题(我是这样的)&#xff0c;装完用 python -m xformers.info 这个看对应的版本 建议&#xff1a;有些命令安装在venv 虚拟机中做&…

【Go实现】实践GoF的23种设计模式:桥接模式

上一篇&#xff1a;【Go实现】实践GoF的23种设计模式&#xff1a;解释器模式 简单的分布式应用系统&#xff08;示例代码工程&#xff09;&#xff1a;https://github.com/ruanrunxue/Practice-Design-Pattern–Go-Implementation 简介 GoF 对桥接模式&#xff08;Bridge Patt…

Android13 CameraServer启动流程

代码入口 frameworks/av/camera/cameraserver 里面包含了四个文件 我们先来看看Android.bp的内容 package {// See: http://go/android-license-faq// A large-scale-change added default_applicable_licenses to import// all of the license_kinds from "frameworks_a…

Flutter第七弹 网格列表GridView

1) Flutter提供了网格列表&#xff0c;怎么设置列数&#xff1f; 2&#xff09;怎么初始化每个列表项Item&#xff1f; 一、GridView简介 Flutter也存在网格列表组建GridView&#xff0c;用于展示多行多列的列表。 1.1 GridView构建 采用GridView.count() 进行构建 1.2 Gr…

服务器代理

服务器代理 配置&#xff1a;64G内存1 3090&#xff08;24g&#xff09;1P4000&#xff08;8g&#xff09; SSH连接 工作路径&#xff1a;/home/ubuntu/workspace/python Anaconda路径&#xff1a;/home/Ubuntu 1.在工作路径下创建自己的文件夹作为workspace 2.以用户ubunbtu登…

数据采集仪:自动化监测系统的核心组件

在当代的工业自动化领域&#xff0c;数据采集仪成为了一个关键的技术工具&#xff0c;它不仅仅是简单地将电信号转化为数据信号&#xff0c;而是能够实时、有效地处理和显示各种信号&#xff0c;确保整个监测系统的稳定、高效运行。 点击输入图片描述&#xff08;最多30字&…

【微信小程序】canvas开发笔记

【微信小程序】canvasToTempFilePath:fail fail canvas is empty 看说明书 最好是先看一下官方文档点此前往 如果是canvas 2d 写canvas: this.canvas,&#xff0c;如果是旧版写canvasId: ***, 解决问题 修改对应的代码&#xff0c;如下所示&#xff0c;然后再试试运行&#x…

春招百题--堆--扩展篇--找出最小

其他类似题目&#xff1a; 373. 查找和最小的 K 对数字378. 有序矩阵中第 K 小的元素719. 找出第 K 小的数对距离786. 第 K 个最小的素数分数 2040. 两个有序数组的第 K 小乘积 2386. 找出数组的第 K 大和 215. 数组中的第K个最大元素 不纠结直接sort排序解决。 class Solut…

[大模型]Yi-6B-Chat 接入 LangChain 搭建知识库助手

Yi-6B-Chat 接入 LangChain 搭建知识库助手 环境准备 在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始…

制作framework

参考学习地址 https://www.jianshu.com/p/a15ad98bc965 注意事项&#xff1a; 1、在自动生成的.h文件中引入头文件时&#xff0c;需要完整路径 2、编译成功后如何查看位置 实际位置在&#xff1a; /Users/apple/Library/Developer/Xcode/DerivedData/项目名称-xaskhaskhkas/…

Zookeeper集群部署

目录 1.环境部署 1.1实验环境 1.2安装前环境 2.安装Zookeeper 2.1修改Zookeeper配置配置文件 2.2 设置myid号以及启动脚本 2.3 设置脚本 2.4 加权并加入系统管理 2.5 分别启动三台机器&#xff08;192.168.247.21&#xff09; 2.6 查看三台主机状态信息 1.环境部署 1…

[java]24:集合

集合&#xff1a; 1&#xff09;可以动态保存任意多个对象&#xff0c;使用比较方便&#xff01; 2)提供了一系列方便的操作对象的方法&#xff1a;add、remove、set、get等3&#xff09;使用集合添加&#xff0c;删除新元素的示意代码-简洁了 集合的框架体系&#xff1a; Java…