数据结构之树知识总结

数据结构之树知识总结

树型结构:

1、树的基本概念

​ 一种表示层次关系(一对多)的数据节构
​ 有且只有一个特定的节点,该节点没有前趋节点,被称为根节点
​ 剩余的n个互不相交的子集,其中每个子集也都是一棵树,都被称为根节点的子树
​ 注意:树型节构具有递归性(树中有树)

2、树的表示方式:

​ 倒悬树、嵌套法、凹凸法

3、树的专业术语

​ 节点:组成树的基础元素,同时它也是一棵树
​ 节点的度:该节点子树的数量
​ 树的度:树中所有节点的度的最大值
​ 树的密度:树中所有节点的数量
​ 树的深度(高度):树的最大层次为树的深度
​ 节点的层次:根节点的层次为1,它的孩子层次为2,孩子的孩子层次为3,以此类推
​ 叶子节点:节点的度为0的节点
​ 双亲节点和孩子节点:节点的子树被称为该节点的孩子节点,该节点就是孩子节点的双亲节点
​ 兄弟节点:具有同一个双亲节点,互为兄弟节点
​ 堂兄弟:双亲节点互为兄弟节点
​ 祖先:从根节点出发到该节点,路径上经过的所有节点都称为该节点的祖先
​ 子孙:一个节点的子树中任意一个节点都是它的子孙

4、树的存储

​ 树可以顺序存储、链式存储,还可以混合存储
​ 可以根据存储的信息不同,树有以下存储方式:

    双亲表示法:    顺序位置    data    双亲下标0       A        -11       B        02       C        03       D        14       E        15       F        16       G        27       H        4 8       X        0 优点:方便找到双亲缺点:查找孩子节点麻烦孩子表示法:顺序:  浪费内存位置    data    son_arr(存储子节点的数组)0       A       1,2,81       B       3,4,52       C       63       D        4       E       7  5       F        6       G        7       H        8       X   链式: 节约内存空间位置    data    ListHead(存储子节点的链表)0       A       1->2->8->N1       B       3->4->5->N2       C       6->N3       D       N 4       E       7->N  5       F       N6       G       N7       H       N8       X       N优点:查找孩子节点方便         缺点:找双亲不方便兄弟表示法:链式双亲只存储第一个子节点 数据 链式指向所有兄弟节点优点:可以方便找到所有的兄弟节点缺点:找双亲麻烦注意:普通树不常用,一般会使用二叉树进行存储
#include <stdio.h> 
#include<stdlib.h> 
#include<stdbool.h> 
#include"link_array_queue.h" 
typedef struct TreeNode 
{ char data; int parent; 
}TreeNode; 
typedef struct Tree 
{ TreeNode *arr; int cnt; int cap; 
}Tree; 
Tree *create_tree(int cap) 
{ Tree *tree=malloc(sizeof(Tree)); tree->arr=malloc(sizeof(TreeNode)*cap); tree->cap=cap; tree->cnt=0; return tree; 
} 
bool add_tree_node(Tree *tree,char data,int pdata) 
{ if('\0'==pdata && tree->cnt==0) { tree->arr[0].data=data; tree->arr[0].parent=-1; tree->cnt++; return true; } for(int i=0;i<tree->cnt;i++) { if(tree->arr[i].data==pdata) { tree->arr[tree->cnt].data=data; tree->arr[tree->cnt++].parent=i; return true; } } 
} 
void show_tree(Tree *tree) 
{ for(int i=0;i<tree->cnt;i++) { printf("index:%d data:%c parent:%d\n",i,tree->arr[i].data,tree->arr[i].parent);	 } 
} 
int _degree(Tree *tree,char data) 
{ int degree=0; int index=-1; for(int i=0;i<tree->cnt;i++) { if(tree->arr[i].data==data) index=i; } if(index==-1)return -1; for(int i=0;i<tree->cnt;i++) { if(tree->arr[i].parent=index) degree++;	 } return degree; 
} 
// 求树的高度 
int _tree_height(Tree *tree,char data)  
{ int index = 0; for (int i = 0; i < tree->cnt; i++)  { if(tree->arr[i].data==data) { index=i; break; } } 
int height=0; for (int j = 0; j < tree->cnt; j++)  { if (tree->arr[j].parent == index)  { int high=_tree_height(tree,tree->arr[j].data); if (high > height)  { height = high; } } } return height+1; 
} 
//求数高度 
int tree_height(Tree *tree) 
{ 
return	_tree_height(tree,tree->arr[0].data);	 
} 
//层次遍历 
void layer_show_tree(Tree *tree) 
{ ListQueue *queue=create_list_queue(); push_list_queue(queue,tree->arr[0].data); while(!empty_list_queue(queue)) { //出队一个结点并显示 char data=head_list_queue(queue); pop_list_queue(queue); printf("%c\n",data); //找出结点的子结点入队 int index;//先找到节点的下标 for(int i=0;i<tree->cnt;i++) { if(data==tree->arr[i].data) { index=i; break; } } for(int i=0;i<tree->cnt;i++) { if(index==tree->arr[i].parent) { push_list_queue(queue,tree->arr[i].data);	 } } } destroy_list_queue(queue); 
} 
int main(int argc, const char* argv[]) 
{ Tree *tree = create_tree(10); add_tree_node(tree, 'A', '\0'); // 添加根节点 add_tree_node(tree, 'B', 'A'); // 添加子节点B,父节点为A add_tree_node(tree, 'C', 'A'); // 添加子节点C,父节点为A add_tree_node(tree, 'D', 'B'); // 添加子节点D,父节点为B add_tree_node(tree, 'E', 'B'); // 添加子节点E,父节点为B add_tree_node(tree, 'F', 'C'); // 添加子节点F,父节点为C show_tree(tree); layer_show_tree(tree); printf("Degree of node B: %d\n", _degree(tree, 'B')); // 测试计算节点B的度数 printf("Degree of node A: %d\n", _degree(tree, 'A')); // 测试计算节点A的度数 printf("Height of tree: %d\n", tree_height(tree)); // 测试计算树的高度 return 0; 
} 
link_array_queue.h

#ifndef QUEUE_H
#define QUEUE_H#include <stdio.h>
#include<stdlib.h>
#include<stdbool.h>#define TYPE int//节点
typedef struct Node
{TYPE data;struct Node *next;
}Node;//创建节点
Node *create_Node(TYPE val);//链队列
typedef struct ListQueue
{Node *front;Node *rear;size_t cnt;}ListQueue;//创建链队列
ListQueue *create_list_queue(void);
//空队列
bool empty_list_queue(ListQueue *queue);//入队
void push_list_queue(ListQueue *queue,TYPE val);//出队
bool pop_list_queue(ListQueue *queue);//队头
TYPE head_list_queue(ListQueue *queue);
//队尾
TYPE tail_list_queue(ListQueue *queue);//队列元素数量
size_t size_list_queue(ListQueue *queue);
//销毁
void destroy_list_queue(ListQueue *queue);#endif //QUEUE_H

二叉树:

​ 是一种常用的数据结构,比普通树处理起来要简单,而且普通树也比较方便地转换成二叉树

  1. 定义:节点的度最多为2

    ​ 二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点

2.特殊的二叉树类型:

​ 满二叉树:每层的节点数都是2^(i-1)
​ 完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树

3.二叉树的重要性质:(重点)

性质1:二叉树的第i层上至多有2^(i-1)(i≥1)个节点
性质2:深度为h的二叉树中至多含有2^h-1个节点
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1
性质4:具有n个节点的满二叉树深为log2n+1
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:
当i=1时,该节点为根,它无双亲节点
当i>1时,该节点的双亲节点的编号为i/2。
若2i≤n,则有编号为2i的左节点,否则没有左节点
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点

练习题:

1.已知一棵二叉树中,有20个叶子结点,其中10个结点只有
左孩子,15个结点只有右孩子,求该二叉树的总结点数。
2.求100个结点的完全二叉树的叶子结点数
3.完全二叉树的第7层有10个叶子结点,总共有多少个叶子结点
4.判断题:完全二叉树最多有1个度为1的结点

二叉树的操作:
构建、销毁、遍历、高度、密度、插入、删除、查询、求左、求右、求根二叉树的存储:顺序存储:必须按照完全二叉树的格式,把每个节点按照从上到下、从左到右的顺序依次存入连续的内存中,如果有空位置则使用特殊数据代替存入数据项:存储节点的内存首地址容量链式存储:由一个个链式节点组成,每个节点就是一棵树节点数据项:数据左子树指针右子树指针        
二叉树的遍历(重点)前序:根、左、右中序:左、根、右后序:左、右、根层序:从上到下、从左到右依次遍历一棵树注意:前中后由根节点决定,并且左右子树的遍历顺序不会改变注意:根据 前序+中序 或者 后序+中序 就可以还原一棵树,只有 前序+后序 是无法还原的注意:层序遍历必须配合队列进行

实现二叉树:

顺序表实现二叉树:http://t.csdnimg.cn/dFnfB

链表实现二叉树:http://t.csdnimg.cn/AHxLJ

有序二叉树

​ 左子树的数据小于根,右子树的数据大于等于根,这种树称为有序二叉树、二叉搜索树、二叉排序树
​ 注意:这种树的节点需要频繁地插入、删除,因此不适合顺序存储
​ 注意:插入、删除都要保证有序

有序二叉树的中序遍历刚好就是从小到大,所以有序二叉树也是一种排序算法,查找又天然是二分查找,所以经常考

有序二叉树实现:http://t.csdnimg.cn/40LyH

二叉树练习题

1、把一棵二叉树转换为它的镜像树。
2、输入两棵二叉树A,B,判断B是不是A的子结构(我们约定空树不是任意一个树的子结构)。
3、将一棵有序二叉树转换成一个有序的双向链表。
4、计算出有序二叉树中倒数第K个大的数。
5、判断一个二叉树是否对称。
6、请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

解题思路:

//镜像树
void mirror_tree(TreeNode *root)
{if(root==NULL)return;TreeNode *temp=root->left;root->left=root->right;root->right=temp;mirror_tree(root->left);mirror_tree(root->right);
}//输入两棵二叉树A,B,判断B是不是A的子结构(我们约定空树不是任意一个树的子结构)。
bool is_same_tree(TreeNode* A, TreeNode* B) {if (B == NULL)  return true; if (A == NULL) return false;if (A->data != B->data)   return false; // 数据不相等,不是子结构return is_same_tree(A->left, B->left) && is_same_tree(A->right, B->right);
}bool is_child_tree(TreeNode* parent, TreeNode* child) {if (parent == NULL || child == NULL) {return false; // 空树不是任意一个树的子结构}if (is_same_tree(parent, child)) {return true; // 完全匹配,是子结构}return is_child_tree(parent->left, child) || is_child_tree(parent->right, child);
}//将二叉树转换成链表//尾添加链表
void _add_tail_list(TreeNode **head,TreeNode *node)
{if(NULL==*head)*head=node;else{(*head)->left->right=node;node->left=(*head)->left;}(*head)->left=node;
}//
void _tree_to_list(TreeNode *root,TreeNode **head)
{if(NULL==root)return;//按照中序添加到链表_tree_to_list(root->left,head);_add_tail_list(head,root);_tree_to_list(root->right,head);
}//
TreeNode *tree_to_list(TreeNode *root)
{TreeNode *head=NULL;_tree_to_list(root,&head);head->left->right=head;return head;
}//判断一个二叉树是否对称。
bool check(TreeNode* node1, TreeNode* node2)
{if(!node1 && !node2) return true;if((!node1 && node2) || (node1 && !node2)) return false;//都不为空,但是val不同if(node1->data != node2->data)  return false;//都不为空,但是val相同,还要看这两棵树是否是镜像的,要分别看外侧和内侧bool outside = check(node1->left, node2->right);bool inside = check(node1->right, node2->left);return outside && inside;}bool isSymmetric(TreeNode* root) {if(!root)return true;return check(root->left, root->right);}//请实现一个函数按照之字形打印二叉树
void printf_zhi(TreeNode *root)
{if (NULL == root) return;ListStack *stack1 = create_Link_stack();ListStack *stack2 = create_Link_stack();push_Link_stack(stack1, root->data); // 将根节点入栈bool left_to_right = true; // 标记从左往右打印while (!empty_list_stack(stack1) || !empty_list_stack(stack2)){ListStack *current_stack = left_to_right ? stack1 : stack2;ListStack *next_stack = left_to_right ? stack2 : stack1;while (!empty_list_stack(current_stack)){TREE_TYPE data = top_list_stack(current_stack);printf("%c ", data);pop_List_stack(current_stack);TreeNode *current_node = find_node(root, data); // 找到当前节点if (current_node != NULL){if (left_to_right){if (current_node->left != NULL) push_Link_stack(next_stack, current_node->left->data);if (current_node->right != NULL) push_Link_stack(next_stack, current_node->right->data);}else{if (current_node->right != NULL) push_Link_stack(next_stack, current_node->right->data);if (current_node->left != NULL) push_Link_stack(next_stack, current_node->left->data);}}}left_to_right = !left_to_right; // 切换方向}
}

线索二叉树:

​ 规律:在n个节点的链式二叉树中必定有n+1个空指针域
​ 有序链式二叉树中有很多的空指针,可以让这些指针指向下一个、前一个节点,这样在遍历时可以不用递归而可以使用循环遍历,可以提高树的遍历速度

中序线索二叉树节点数据项:数据左子树指针右子树指针右子树指针标志位 (假表示指向真的右子树,真表示右子树指向下一个节点)实现过程:1、构建有序二叉树2、创建线索3、通过线索循环遍历二叉树

线索二叉树的实现:

#include <stdio.h>
#include<stdlib.h>
#include<stdbool.h>typedef struct TreeNode
{int data;struct TreeNode *left,*right;bool rclue;
}TreeNode;TreeNode *create_node(int data)
{TreeNode *node=malloc(sizeof(TreeNode));node->data=data;node->left=NULL;node->right=NULL;node->rclue=false;return node;
}
void _insert_tree(TreeNode **root,TreeNode *node)
{if((*root)==NULL){*root=node;	return;}if(node->data<(*root)->data)_insert_tree(&(*root)->left,node);else_insert_tree(&(*root)->right,node);
}void insert_tree(TreeNode **root,int data)
{_insert_tree(root,create_node(data));	
}void dlr_show(TreeNode *root)
{if(NULL==root)return ;dlr_show(root->left);printf("%d ",root->data);dlr_show(root->right);
}
//上一个节点
TreeNode *prev=NULL;//按照中序遍历,创建线索
void create_clue(TreeNode *root)
{if(NULL==root)return;create_clue(root->left);if(NULL!=prev&&NULL==prev->right){prev->rclue=true;prev->right=root;}prev=root;create_clue(root->right);
}void clue_show(TreeNode *node)
{while(node){while(node->left){node=node->left;}printf("%d ",node->data);while(node->rclue){node=node->right;printf("%d ",node->data);}node=node->right;}printf("\n");
}int main(int argc,const char* argv[])
{TreeNode *root=NULL;for(int i=0;i<10;i++){int data=rand()%100;insert_tree(&root,data);}dlr_show(root);create_clue(root);printf("\n-----------------\n");clue_show(root);
}

选择树:(胜者树、败者树)

​ 是一种完全二叉树,待比较的数据都存储在最后一层,根节点是根据左右子树其中一个生成,因此根节点是最大或者最小的,选择树的功能是快速地找出最大值或最小值

堆:

​ 是一种完全二叉树,不适合链式存储
​ 大顶堆(大根堆):根节点比左右子树大
​ 小顶堆(小根堆):根节点比左右子树小
​ 数据项:
​ 存储数据的内存首地址
​ 容量
​ 数量
​ 操作:创建、销毁、添加、删除、空堆、满堆
​ 堆可以实现优先队列的效果
堆实现:

#include <stdio.h>
#include<stdlib.h>
#include<stdbool.h>#define TYPE int
#define swap(a,b) {typeof(a) t=(a);(a)=(b);(b)=t;}typedef struct Heap
{TYPE *arr;int cap;int cnt;
}Heap;//创建堆
Heap *create_heap(int cap)
{Heap *heap=malloc(sizeof(Heap));heap->arr=malloc(sizeof(TYPE)*cap);heap->cap=cap;heap->cnt=0;return heap;
}//空堆
bool empty_heap(Heap *heap)
{return !heap->cnt;	
}
//满堆
bool full_heap(Heap *heap)
{return heap->cnt==heap->cap;	
}//添加
bool add_heap(Heap *heap ,TYPE data)
{if(full_heap(heap))return false;heap->arr[heap->cnt++]=data;//添加后调整为堆int i=heap->cnt;while(i>1){if(heap->arr[i/2-1]>heap->arr[i-1]){swap(heap->arr[i/2-1],heap->arr[i-1]);	}i=i/2;}return true;
}//删除
bool del_heap(Heap *heap)
{if(empty_heap(heap))return false;//堆顶与末尾交换swap(heap->arr[0],heap->arr[heap->cnt-1]);//删除末尾heap->cnt--;//从上往下调整int i=1;while(i-1<heap->cnt){if(i*2<heap->cnt){if(heap->arr[i*2]>=heap->arr[i*2-1] && heap->arr[i-1]<heap->arr[i*2]){swap(heap->arr[i-1],heap->arr[i*2]);i=i*2+1;}else if(heap->arr[i*2]<heap->arr[i*2-1] && heap->arr[i*2-1]>heap->arr[i-1]){swap(heap->arr[i-1],heap->arr[i*2-1]);i=i*2;}elsebreak;}else if(i*2-1<heap->cnt){if(heap->arr[i*2-1]>heap->arr[i-1]){swap(heap->arr[i*2-1],heap->arr[i-1]);i=i*2;}else{break;	}}elsebreak;}return true;
}//调整为大根堆
void _Heap_adjust(Heap *heap, size_t action, size_t pos)
{int i = action + 1;while (i * 2 <= pos){int j = i * 2;if (j < pos && heap->arr[j - 1] > heap->arr[j]){j++;}if (heap->arr[i - 1] <= heap->arr[j - 1]){break;}swap(heap->arr[i - 1], heap->arr[j - 1]);i = j;}
}
//查看全部
void show_heap(Heap *heap)
{for(int i=0;i<heap->cnt;i++){printf("%d ",heap->arr[i]);	}printf("\n");
}//堆顶
TYPE show_top_heap(Heap *heap)
{return heap->arr[0];	
}
//堆排序 循环实现
void heap_sort_for(Heap *heap)
{for(int i=heap->cnt;i>0;--i){swap(heap->arr[0],heap->arr[i-1])_Heap_adjust(heap,0,i-1);}
}//堆排序 递归实现
void _heap_justify(Heap *heap, size_t action, size_t pos)
{size_t lh = action * 2 + 1;size_t rh = action * 2 + 2;size_t largest = action;if (lh < pos && heap->arr[lh] > heap->arr[largest]) {largest = lh;}if (rh < pos && heap->arr[rh] > heap->arr[largest]) {largest = rh;}if (largest != action) {swap(heap->arr[action], heap->arr[largest]);_heap_justify(heap, largest, pos);}
}void heap_sort(Heap *heap)
{for (int i = heap->cnt - 1; i >= 0; --i){swap(heap->arr[0], heap->arr[i]);_heap_justify(heap, 0, i);}
}
int main(int argc,const char* argv[])
{Heap *heap=create_heap(10);for(int i=0;i<10;i++){int data=rand()%100;add_heap(heap,data);}show_heap(heap );printf("TOP:%d\n",show_top_heap(heap));heap_sort(heap);show_heap(heap);
}

平衡二叉搜索树(AVL树):

​ 前提是有序的二叉树,它的左右子树的高度差不超过1,而且它的所有子树也满足这个条件
​ 如果一个有序二叉树呈现接近单支状(类似链表),它的查找效率接近链表,因此只有达到平衡时它的查找效率最高
​ 由于节点的值受限,因此只能通过调整达到有序,而不能进行值的修改
​ 二叉树不平衡的基础原因:
​ x y
​ / \ /
​ y t1 以y为轴向右旋转 z x
​ / \ / \ /
​ z t2 t3 t4 t2 t1
​ /
​ t3 t4

    x                                  y/ \                              /     \t1  y        以y为轴向左旋转      x       z/ \                         /   \    /  \ t2  z                       t1   t2  t3  t4/ \t3  t4x               x                  z/ \             / \               /   \y   t1          z   t1            y     x/ \             / \              /  \   /  \
t2  z           y   t4           t2  t3 t4   t1 / \         / \t3 t4       t2 t3 
以z为轴向左旋转   以z为轴向右旋转    最终平衡x                x                  z/ \              / \              /      \t1  y            t1  z            x        y  / \              / \          /  \    /   \z   t2           t3  y        t1  t3  t4   t2/ \                  / \t3 t4                t4  t2
以z为轴右旋       以z为轴左旋           最终平衡

平衡二叉树代码实现:http://t.csdnimg.cn/rrT6Z

红黑树:

​ 也是一种自平衡的树,它不是根据子树的高度差来调整平衡的,而是给节点设置一种颜色,来达到平衡
​ 红黑树的特性:
​ 1、每个节点或者是黑色、或者是红色
​ 2、根节点必须是黑色
​ 3、每个叶子节点(NULL)是黑色
​ 4、如果一个节点是红色,则它的子节点必须是黑色
​ 不能有两个连续的红色节点
​ 5、从一个节点到该节点的子孙节点的所有路径上包含了相同数量的黑色节点
​ 保证大致上红黑树是平衡的(最长路径不超过最短路径的两倍)

红黑树插入后的调整:插入的节点一定是红色1、如果父节点是黑色,直接插入2、如果父节点是红色,需要调整a、叔叔不存在 or 叔叔为黑色进行 左旋 or 右旋祖父节点置红 父节点置黑b、叔叔存在且为红色祖父置红,父节点和叔叔置黑把祖父节点当做当前节点,继续向上讨论调整优点:插入、删除的效率比AVL树高
缺点:没有AVL树平均,查找效率没有AVL树高,但也并不差

哈夫曼树:

​ 基本概念:
​ 路径长度:从一个节点到另一个节点之间的路径条目数
​ 根节点到第n层节点的路径长度为 n-1
​ 树的路径长度:从根节点出发到每个节点的路径长度之和
​ 节点的权:若将树中节点赋予一个有某种意义的数值,该数值称为该节点的权
​ 节点的带权路径长度:从根节点到该节点的路径长度与该节点的权的乘积
​ 树的带权路径长度:所有的叶子节点的带权路径长度之和,称为WPL
​ WPL是衡量一棵带权二叉树优劣的关键

例子:
成绩:  <60     60~69   70~79   80~89   90~100
等级:  E         D       C       B       A
比例:  5%       15%     40%     30%     10%普通带权二叉树的WPL:5*1+15*2+40*3+30*4+10*4=315
哈夫曼树的WPL:40+2*30+3*15+4*10+4*5 = 205哈夫曼树的目的是为了生成一棵WPL最小的的带权二叉树
构建哈夫曼树:1、把n个带权节点存入一个集合F中,把每个节点左右子树置空2、从F中选取权值最小的两个节点作为左右子树构建成一棵新的二叉树,且新的根节点的权为左右子树的权值之和3、从F中删除刚刚选出来的两个节点,把新得到的根节点放入F中4、重复2、3步骤,直到F中只剩下一棵树,既是哈夫曼树

哈夫曼编码:

​ 目的:解决当年远距离通信(电报)的数据传输的最优解
​ 待发送的文字:BADCA DFEED
​ 方法1:转成二进制发送 A 000 B 001 共30个字符
​ 方法2:
​ a、根据文字出现频率,构建哈夫曼树
​ 假设频率: A27 B8 C15 D15 E30 F5
​ b、规定哈夫曼树的左分支为0,右分支为1,则从根节点到叶子节点经过的路径分支所组成的0、1序列为该对应字符的哈弗曼编码
​ 哈夫曼编码:A01 B1001 C101 D00 E11 F1000
​ 1001010010101001000111100 共25个字符
​ 作用:数据压缩、文件压缩的其中一种方式

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

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

相关文章

C语言 ——— 数组指针的定义 数组指针的使用

目录 前言 数组指针的定义 数组指针的使用 前言 之前有编写过关于 指针数组 的相关知识 C语言 ——— 指针数组 & 指针数组模拟二维整型数组-CSDN博客 指针数组 顾名思义就是 存放指针的数组 那什么是数组指针呢&#xff1f; 数组指针的定义 何为数组指针&#xf…

【QT】UDP

目录 核心API 示例&#xff1a;回显服务器 服务器端编写&#xff1a; 第一步&#xff1a;创建出socket对象 第二步&#xff1a; 连接信号槽 第三步&#xff1a;绑定端口号 第四步&#xff1a;编写信号槽所绑定方法 第五步&#xff1a;编写第四步中处理请求的方法 客户端…

JAVA开发工具IDEA如何连接操作数据库

一、下载驱动 下载地址&#xff1a;【免费】mysql-connector-j-8.2.0.jar资源-CSDN文库 二、导入驱动 鼠标右击下载到IDEA中的jar包&#xff0c;选择Add as Library选项 如图就导入成功 三、加载驱动 Class.forName("com.mysql.cj.jdbc.Driver"); 四、驱动管理…

最新站长工具箱源码,拥有几百个功能,安装教程

最新站长工具箱源码&#xff0c;拥有几百个功能&#xff0c;安装教程 在 Docker 上运行 docker run -e LAFREGIONCN -e APPLANGzh_CN --name my-miaoda -v ~/.miaoda-docker:/root/.miaoda -d -p 0.0.0.0:39899:39899 codegentoolbox/laftools-linux-x64:latestNOTE: 默认端…

【C++】——红黑树(手撕红黑树,彻底弄懂红黑树)

目录 前言 一 红黑树简介 二 为什么需要红黑树 三 红黑树的特性 四 红黑树的操作 4.1 变色操作 4.2 旋转操作 4.3 插入操作 4.4 红黑树插入代码实现 4.5 红黑树的删除 五 红黑树迭代器实现 总结 前言 我们之前都学过ALV树&#xff0c;AVL树的本质就是一颗平…

计算机实验室排课查询小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;实验室信息管理&#xff0c;实验室预约管理&#xff0c;取消预约管理&#xff0c;实验课程管理&#xff0c;实验报告管理&#xff0c;报修信息管理&#xff0…

【Python】如何在 Python 中操作 Excel

Python 操作 Excel 文件 1. 常用的几种库 xlrd和xlwt库 xlrd&#xff1a;用于读取Excel文件。xlwt&#xff1a;用于写入Excel文件。这两个库通常一起使用&#xff0c;xlrd用于读取&#xff0c;xlwt用于写入&#xff0c;但它们不支持Excel 2007及以后的.xlsx格式。 openpyxl库…

Linux的yum源安装MySQL5.7

linux的yum源安装MySQL5.7 一、MySQL 1、简介 MySQL 是一种流行的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典公司 MySQL AB 开发&#xff0c;后来被 Oracle Corporation 收购。它是一个开源软件&#xff0c;提供了高效、稳定和可靠的数据管理解决…

【Spring Framework】Spring 事务使用的完整示例

为了详细展示 Spring 事务的使用&#xff0c;我将提供一个完整的示例&#xff0c;包括配置、代码和说明。这将涵盖以下几个方面&#xff1a; 数据库配置&#xff1a;包括数据源和事务管理器的配置。实体类&#xff1a;用于数据库操作的数据模型。DAO 层&#xff1a;数据访问对…

Android SurfaceFlinger——GraphicBuffer的提交(三十三)

在 SurfaceFlinger 中,我们 dequeueBuffer 和 queueBuffer 是 Surface 控制接口中非常重要的两个函数,分别用于从 Surface 的 BufferQueue 中取出缓冲区和向 BufferQueue 提交(队列)缓冲区。这两个函数在生产者和消费者模型中扮演着核心角色,确保了图像数据的高效和有序传…

消息队列原理题库

1. 简述什么是消息队列 &#xff1f; 消息&#xff08;Message&#xff09;是指在应用间传送的数据。消息可以非常简单&#xff0c;比如只包含文本字符串&#xff0c;也可以更复杂&#xff0c;可能包含嵌入对象。 消息队列&#xff08;Message Queue&#xff09;是一种应用间…

【算法】子集

难度:中等 题目: 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 示例 2: 输入…

Spring AI (三) 提示词对象Prompt

3.提示词对象Prompt 3.1.Prompt Prompt类的作用是创建结构化提示词, 实现了ModelRequest<List<Message>>接口 Prompt(String contents)&#xff1a;创建一个包含指定内容的Prompt对象。 Prompt(String contents, ChatOptions modelOptions)&#xff1a;创建一个…

某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]

文章目录 某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内…

DolphinDB Web 端权限管理:可视化操作指南

在现代数据库管理中&#xff0c;高效和直观的权限管理对于用户的数据安全是至关重要的。过去 DolphinDB 用户需要依赖系统脚本来管理用户和权限&#xff0c;这对于缺乏技术背景的管理员来说既复杂又容易出错。 为了提升用户体验和操作效率&#xff0c;DolphinDB 目前在 Web 上…

数据库设计三范式

文章目录 数据库设计三范式第一范式第二范式第三范式一对一怎么设计主键共享外键唯一 一对多怎么设计多对多怎么设计 数据库设计三范式 数据库表设计的原则。教你怎么设计数据库表有效&#xff0c;并且节省空间。 如果客户有速度要求极致&#xff0c;可以不用。根据客户需求来 …

vue3中动态添加form表单校验

<template><div><div v-for"(formData, index) in forms" :key"index"><u-form :model"formData" :rules"rules" ref"formRefs"><u-form-item label"用户名" prop"username"…

MySQL数据库练习(5)

1.建库建表 # 使用数据库 use mydb16_trigger;# 表格goods create table goods( gid char(8) primary key, name varchar(10), price decimal(8,2), num int);# 表格orders create table orders( oid int primary key auto_increment, gid char(10) not null, name varchar(10…

scrapy 爬取旅游景点相关数据(一)

第一节 Scrapy 练习爬取穷游旅游景点 配套视频可以前往B站&#xff1a;https://www.bilibili.com/video/BV1Vx4y147wQ/?vd_source4c338cd1b04806ba681778966b6fbd65 本项目为scrapy 练手项目&#xff0c;爬取的是穷游旅游景点列表数据 0 系统的环境 现在网上可以找到很多scr…

其它------

这里写目录标题 一级目录二级目录三级目录 一级目录 二级目录 三级目录