提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
树结构是一种非常重要的数据结构
1.二叉树的顺序存储结构:
用一组连续的存储单元依次从上到下、从左到右存储完全二叉树上的结点元素,对于一般的二叉树需要添加存储一些空的结点。因此对于普通的二叉树来说不适合用顺序存储浪费空间,该存储结构适合于完全二叉树。
注意:在树的顺序存储中数组下标仅表示节点的编号,而二叉树的顺序存储结构中数组的下标既表示节点的编号,又表示树中各结点的关系。(节点编号为数组下标编号为i,其左右孩子节点的数组下标为2i和2i+1),根结点存储在第一个位置。
总之,二叉树属于树,二叉树可以用树的存储结构来存储,但树不能用二叉树的存储结构来存储。
练手题:洛谷P1305新二叉树
#include
#define MAX 1e3
struct Data{
int a;
};
Data[MAX];
2.二叉树的链式存储(二叉链表)
#include
struct Data{
int a;
};
typedef struct BiTNode{
Data s;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree L; //表示一棵树
二叉树的遍历是进行二叉树各种操作的基础,可以在遍历的过程中对结点进行各种操作,如对一个已知树,可求结点的双亲或孩子结点,判断结点的层数等,也可以在遍历的过程中生成结点。此外,还有递归使用分治策略求结点的高度。
//递归实现
void PreOrder(BiTree T){
if(T){
printf("%d", T->s.a);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
void InOrder(BiTree T){
if(T){
PreOrder(T->lchild);
printf("%d", T->s.a);
PreOrder(T->rchild);
}
}
void PostOrder(BiTree T){
if(T){
PreOrder(T->lchild);
PreOrder(T->rchild);
printf("%d", T->s.a);
}
}
//非递归实现
//队列实现层次遍历
//先序创建二叉树
void CreateBiTree(BiTree &T){
int temp;
scanf("%d", &temp);
if(temp == -1) T = NULL;
else{
T = (BiTree )malloc(sizeof(BiTNode));
if(!T) return ;
T->a = temp;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
//中序线索二叉树线索化
typedef struct Tree{
Data s;
struct Tree *lchild,*rchild;
int ltag,rtag;
}Tree,*ThreadTree;
void CreateInThread(ThreadTree T){
ThreadTree pre = NULL;
if(T){
InThread(T, pre);
pre->rchild = NULL;
pre->rtag = 1;
}
}
void InThread(ThreadTree &p, ThreadTree &pre){
if(p){
InThread(p->lchild, pre);
if(p->lchild==NULL){
p->lchild = pre;
p->tag = 1;
}
if(pre!=NULL&&pre->rchild==NULL){ //前驱结点
pre->rchild = p;
pre->tag = 1;
}
pre = p;
InThread(p->rchild, pre);
}
}
//中序线索二叉树的遍历
ThreadNode *FristNode(ThreadNode *p){
while(p->ltag == 0)
p = p->lchild;
return p;
}
ThreadNode *NextNode(ThreadNode *p){
if(p->rtag == 0)
return FristNode(p->rchild);
else
return p->rchild;
}
void InOrder(ThreadNode *T){
for(ThreadNode *p = FristNode(T); p!=NULL; p = NextNode(T))
visit(p);
}
每种存储方法需要考虑:结点数据,结点与双亲结点或孩子结点的映射关系,根结点的位置和树的所有结点个数的这些东西的存储。
1.双亲表示法(并查集中最常使用)
用一组连续的空间存储树的结点,每个结点中设置一个变量映射双亲结点的位置即数组下标,便于查找结点的根,对于结点的孩子查找需要遍历整个树
struct Data{
int a;
int parent; //若每个结点存储需要结构体,就可以直接在里面设置指向父结点的游标
};
typedef struct{
Data[MAX]; //存储结点
int n,r; //根的位置和结点数
}PTree;
//int fa[MAX]; //存储每个对应结点的父节点的位置,把父子关系单独存储就显的更加直观
2.孩子表示法(便于查找孩子结点)
typedef struct CTNode{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct{
int data; //数据部分
ChildPtr firstChild; //孩子链表
}CTBox;
typedef struct{
CTBox nodes[MAX]; //存储所有结点的数组
int n, r; //结点数,根结点的位置
}CTree;
3.左孩子右兄弟表示法(树转二叉树的方式)
typedef struct CSNode{
int data;
struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree
一个树型的数据结构,用于处理一些不交集的合并及查询问题,主要操作有:
Find:确定元素属于哪个子集,即找寻根结点,可在递归找寻根结点的途中压缩处理。
Union:将两个不相交的子集合并为同一个集合,先Find根结点,再看是否是同一集合,只有不是才会进行实际合并操作,即一个根结点认另一个根结点叫爸爸。
例题:洛谷P1111修复公路
例题:牛客 黑白边问题
n个点,m条边,每条边分为黑边和白边,现在需要挑一些边出来,使得n个点可以两两联通。由于牛牛特别讨厌白边,所以在挑中的边中,让白边最少,输出白边的条数,如果不能两两联通,输出−1.
输入:
第一行两个整数n,m. 1≤n,m≤2e5
接下来 m 行, 每行三个整数 x,y,z 代表xy之间有一条边。z的值为0或1,0 代表黑边,1代表白边
输出:
一行一个整数, 表示最少的白边数量。如果不能满足题目条件,输出 -1
#include
using namespace std;
const int N = 2e5 + 7;
struct Node{
int x, y, z;
bool operator <(const Node& a) const{
return z < a.z;
}
}Edge[N];
int fa[N];
int find(int x){
return x == fa[x]? x : (fa[x] = f(fa[x]));
}
int main(){
int n = 0, m = 0, ans = 0, total = 0;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &Edge[i].x, &Edge[i].y, &Edge[i].z);
}
for(int i = 1; i <= n; i++) fa[i] = i;
sort(Edge, Edge + m);
for(int i = 0; i < m; i++){
int fx = find(Edge[i].x);
int fy = find(Edge[i].y);
if(fx != fy){
fa[fx] = fa[fy];
total++;
if(Edge[i].z) ans++;
}
if(total == n - 1) break;
}
if(total != n - 1)
printf("-1\n");
else
printf("%d\n", ans);
return 0;
}
/*
输入:
4 4
1 2 0
2 3 0
3 4 1
1 4 0
输出:
0
*/
一种使用顺序存储结构的特殊完全二叉树,
(1)若满足每个结点的关键字大于左右子树所有结点的关键字,则是大顶堆;
(2)若满足每个结点的关键字小于左右子树所有结点的关键字,则是小顶堆;
步骤:
(1)构造堆
(2)维护堆
应用问题:
堆排序
TOP k问题(海量数据查找k个最大或最小的数):先取K个数建立堆,再不断push()一个,pop()一个,每次在插入后K+1个数据中淘汰1个数据。
注意:C++STL中的priority_queue就是默认大顶堆,可重载比较运算符或者对sort方法新建比较器使其改变为小顶堆,具体运用可以直接用优先队列来实现堆,不必手写,当然你乐意的话,也可以手写堆。
常见的索引结构,数据库中索引有所应用
属于自平衡的搜索二叉树,C++STL关联容器set/multiset、 map/multimap的底层实现(unorder_map和unorder_set底层实现是哈希结构)
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。