二叉树+二叉树搜索树+堆

简介:                                           二叉树 二叉树的几个性质 1在二叉树的第i层最多有2^(i-1)个节点 2深度为k的二叉树最少有k个节点,最多2^k-1个节点 3对于任何一颗非空二叉...

                                          二叉树

二叉树的几个性质

1在二叉树的第i层最多有2^(i-1)个节点

2深度为k的二叉树最少有k个节点,最多2^k-1个节点

3对于任何一颗非空二叉树,如果其叶子节点数为n0,度为2的非叶子节点个数为n2= n0-1

4具有n个节点的完全二叉树的深度为log(n+1)

5有前序序列和中序序列可以唯一确定一颗二叉树

6如果有n个节点,那么二叉树的不同形态有[1/(n+1)]*[(2n)!/(n!*n!)](这与1...n进栈问有几种出栈顺序相同)

7一棵有n个节点的完全二叉树的第一个非叶子节点的编号为n/2(节点编号1~n

//1二叉树的结构
struct Tree{
   Tree *L_child;
   Tree *R_child;
   Tree *father;
   int level;//当前节点在第几层
   char value//节点的数据
   Tree(char ch){//构造函数
      L_child = NULL;
      R_child = NULL;
      father = NULL;
      value = ch;
   }
};

//2利用前序序列建立二叉树
//例如"ABC##DE#G##F###",返回根节点
Tree* buildTree(Tree *root){
    char ch;
    cin>>ch;
    if(ch == '#')
      root = NULL;
    else{
      root = new Tree(ch);
      buildTree(root->L_child);
      buildTree(root->R_child);
    }
    return root;
}

//3二叉树的遍历
//前序遍历二叉树
void preOrder(Tree *u){
    if(u != NULL){
      printf("%c" , u->value);
      PreOrder(u->L_child);
      PreOrder(u->R_child);
    }
}

//中序遍历二叉树
void inOrder(Tree *u){
    if(u != NULL){
       inOrder(u->L_child);
       printf("%c" , u->value);
       inOrder(u->R_child);
    }
}

//后序遍历二叉树
void postOrder(Tree *u){
    if(u != NULL){
       postOrder(u->L_child);
       postOrder(u->R_child);
       printf("%c" , u->value);
    }
}

//层次遍历二叉树
void levelOrder(Tree *root){
    queue<Tree*>q;
    q.push(root);
    while(!q.empty()){
        Tree *tmp = q.front();
        q.pop();
        printf("%c" , tmp->value);
        if(tmp->L_child != NULL)
           q.push(tmp->L_child);
        if(tmp->R_child != NULL)
           q.push(tmp->R_child);
    }
}

//4二叉树的计数
//计算二叉树的节点的个数(等于左子树+右子树+根节点)
int size(Tree *root){
   if(root == NULL)
      return 0;
   else
      return 1+size(root->L_child)+size(root->R_child);
}

//计算二叉树的高度(如果二叉树为空那么高度为0,否则高度就是取左右子树中高的那个+根节点)
int high(Tree *root){
   if(root == NULL)
      return 0;
   else{
      int left = high(root->L_child);
      int right = high(root->R_child);
      return left < right ? right+1 : left+1;
   }
}

//5二叉树的复制,返回复制后的根节点
Tree * copy(Tree *root){
   if(root == NULL)
      return NULL;
   Tree *tmpRoot = new Tree(root->value);
   tmpRoot->L_child = copy(root->L_child);
   tmpRoot->R_child = copy(root->R_child);
   return tmpRoot;
}

//6判断两棵二叉树是否相等
bool isEqual(Tree* root1 , Tree *root2){
   if(root1 == NULL && root2 == NULL)
      return true;
   if(root1 != NULL && root2 != NULL && root1->value == root2->value
      &&isEqual(root1->L_child, roo2->L_child)//左子树相等
      &&isEqual(root1->R_child, roo2->R_child)//右子树相等
      )
      return true;
   else
      return false;
}

//7二叉树的重建(节点编号从1~n)
由前序序列和中序序列构造二叉树(len是序列的长度,pre为前序序列 mid为中序序列,返回根节点)
Tree* buildTree(char *pre , char *mid , int len){
   if(!len)
     return NULL;
   int k = 0;
   while(pre[0] != mid[k])//在中序序列找根节点
       k++;
   Tree *root = new Tree(pre[0]);//创建根节点
   root->L_child = buildTree(pre+1 , mid , k);//左边k个元素是左子树的
   root->R_child = buildTree(pre+k+1 , mid+K+1 , len-k-1);//右边len-k-1个元素是右子树的,扣除根节点
   return root;
}

//由中序和后序建立二叉树(len是序列的长度,mid是中序序列,post是后序序列,返回根节点)
Tree* buildTree(char *mid , char *post , int len){
   if(!len)
     return NULL;
   int k = 0;
   while(mid[k] != post[len-1])//在中序序列中找根节点,这里要len-1
       k++;
   Tree *root = new Tree(post[len-1]);
   root->L_child = buildTree(mid , post , k);//左边k个元素是左子树的
   root->R_child = buildTree(mid+k+1 , pos+k , len-k-1);//右边len-k-1个元素是右子树的,扣除根节点
   return root;
}

//8作用:无跟树转化为有根树
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 15;
vector<int>v[MAXN];
int fa[MAXN];

void dfs(int u , int f){
    fa[u] = f;
    int size = v[u].size();//求出和点u相连的点的个数
    for(int i = 0 ; i < size ; i++){
       int tmp = v[u][i];
       if(tmp != f)
          dfs(tmp , u);
    }
}

int main(){
    int n , x , y;
    scanf("%d" , &n);
    for(int i = 0 ; i < n ; i++){
       scanf("%d%d" , &x , &y);
       v[x].push_back(y);
       v[y].push_back(x);
    }
    dfs(1 , -1);//这里举例1为根,我们传人其它的节点作为根节点
    return 0;
}

 


                                                                                         二叉树索树

二叉搜索树的性质
1 二叉搜索树可以是一棵空树
2 二叉搜索树的每个节点的值都互不相同
3 二叉搜索树的左子树上的所有节点值都小于根节点的值,右子树上的所有
节点的值都大于根节点的值,左右子树都是二叉搜索树
4 对二叉搜索树进行中序遍历,可以按从小到大排列起来
5 假设有n个节点,那么就有(1/(n+1))*((2n)!/(n!*n!))种可能的二叉搜索树形态
6 在随机情况下具有n个节点的二叉搜索树的插入,删除,搜索的时间复杂度为O(logn)。

//1 二叉搜索树的结构体
struct Tree{
   Tree* L_child;
   Tree* R_child;
   int num;
   Tree(int x){
      num = x;
      L_child = R_child = NULL;
   }
};
Tree* root;//全局变量

//2 建立二叉搜索树
//(做法是假设有n个节点那么插入n次)
void buildTree(int x , Tree *&u){
   if(u == NULL)//建立根节点
      u = new Tree(x);
   else if(u->num == x)//已经有了不用在插入
      return ;
   else if(x < u->num)
      buildTree(x , u->L_child);
   else 
      buildTree(x , u->R_child);
}

//3 二叉搜索树的搜索
bool search(int x , Tree *u){
   if(u == NULL)
     return false;
   else if(u->num == x)
     return true;
   else if(x < u->num)
     return search(x , u->L_child);
   else
     return search(x , u->R_child);
}

//4 二叉搜索树的删除
 //1 假设要删除的节点只有做儿子或右儿子,那么用这个唯一的儿子节点代替该节点,删除之。
 //2 假设要删除的节点有两个儿子节点,那么就是找到右子树中中序下的第一个节点代替该节点,然后删除该节点并递归向下删除
void remove(int x , Tree *u){
    if(u == NULL)
        return;
    else if(x < u->num)
      remove(x , u->L_child);
    else if(x > u->num)
      remove(x , u->R_child);
    else{
      if(u->L_child != NULL && u->R_child != NULL){
        Tree *tmp = u->R_child;
        while(tmp->L_child != NULL)
             tmp = tmp->L_child;
        u->num = tmp->num;
        remove(u->num , u->R_child);
      }
      else{
        Tree *tmp = u;
        if(u->L_child == NULL)
          u = u->R_child;
        else
          u = u->L_child;
        delete tmp;
      }
    }
}


                                             堆

堆的性质

1堆是一棵完全二叉树

2最小堆是指所有的节点都满足根节点的值小于等于左右儿子节点的值,最大堆则是所有的节点都满足根节点的值大于等于左右儿子节点的值

3假设有n个元素的无序序列heap[n]编号从1~n,现在要建一个最小堆。

算法是从第一个非叶子节点开始往上调整即可。

//1 n/2次的调整(每一次内部可能还需从上往下调整) , 因为第一个非叶子节点肯点是n/2
void buildHeap(){
   for(int i = n/2 ; i >= 1 ; i--)
      adjustUp(i,n);
}
//2 从上往下调整
void adjustDown(int num , int size){
   //num是当前要调整的编号,size是堆的最大的元素个数
   int L_child , R_child , min;
   L_child = 2*num , R_child = 2*num+1 , min = num;
   if(L_child <= size && heap[L_child] < heap[min])
      min = L_child;
   if(R_child <= size && heap[R_child] < heap[min])
      min = R_child;
   if(min != num){
      swap(heap[num] , heap[min]);
      adjustDown(min , size);//还要继续向下调整
   }
}
//3 最小堆中插入元素
(做法是先插入最后一个元素的下个位置,然后从下往上调整成最小堆)
(curSize是当前的最后一个元素的下标(1开始),maxSize是最大的元素的个数)
void insert(int x){
   if(curSize == maxSize)   
      return;
   heap[++curSize] = x;
   adjustUp(curSize);
}
//4 从下往上调整
void adjustUp(int num){
   int cur = num;
   int father = cur/2;
   while(cur > 0){
      if(heap[cur] < heap[father]){
         swap(heap[cur] , heap[father]);
         cur = father;
         father = father/2;
      }
      else//如果是根节点比当前点小或相等那么直接返回,因为已经是最小堆     
        return;
   }
}
//5 最小堆中删除最小值(也就是删除根节点)
(做法是把最后一个元素拿到根节点,然后从上往下调整为最小堆)
void removeMin(){
   if(!curSize)//如果没有元素直接返回
      return;
   swap(heap[1] , heap[curSize]);
   curSize--;//把最后一个隔开
   adjustDown(1,curSize);//从上往下调整为最小堆
}
//6 堆排序(如果要使得队列从小到大)
(做法是假设已经是最大堆,那么就是每次取走根节点的值,把最后一个换上去继续调整为最大堆
 那么如果n个元素只要n-1次最后一个就不用了)。
void heapSort(){
   int size = n;
   for(int i = n ; i >= 2 ; i--){
      swap(heap[1] , heap[i]);      
      size--;//说明后面已经排好序了不用管
      adjustDown(1 , size);//只要调整1~size的即可
   }
}













目录
相关文章
|
6月前
|
前端开发 搜索推荐 数据安全/隐私保护
Calibre-Web-Automated:打造你的私人图书馆
Calibre-Web-Automated 是一个功能强大、易于使用的电子书管理平台,它可以帮助你轻松构建和管理你的私人图书馆。如果你正在寻找一个开源、免费、可定制的电子书管理解决方案,那么 Calibre-Web-Automated 绝对是你的不二之选!
237 10
Calibre-Web-Automated:打造你的私人图书馆
|
7月前
|
存储 监控 算法
EMAS 性能分析全面适配HarmonyOS NEXT,开启原生应用性能优化新纪元
阿里云EMAS(Enterprise Mobile Application Studio,简称EMAS)性能分析现已全面适配华为HarmonyOS NEXT操作系统,为企业客户及开发者提供覆盖应用全生命周期的性能监测与优化解决方案,助力企业抢占鸿蒙生态先机,赋能开发者打造极致体验。
|
7月前
|
人工智能 测试技术
VARGPT:将视觉理解与生成统一在一个模型中,北大推出支持混合模态输入与输出的多模态统一模型
VARGPT是北京大学推出的多模态大语言模型,专注于视觉理解和生成任务,支持混合模态输入和高质量图像生成。
219 22
|
7月前
|
数据库
【YashanDB 知识库】数据库一主一备部署及一主两备部署时,主备手动切换方法及自动切换配置
**数据库主备切换简介** 在数据库正常或异常情况下,实现主备切换至关重要。若配置不当,主节点故障将影响业务使用,尤其在23.2版本中。原因包括资源紧张或主节点异常。解决方法涵盖手动和自动切换: 1. **一主一备部署**: - **手动切换**:支持Switchover(同步正常时)和Failover(主库损坏时)。 - **自动切换**:启用yasom仲裁选主开关。 2. **一主两备部署**: - 默认最大保护模式,自动切换开启。 需检查并配置自动切换以确保高可用性。经验总结:一主一备默认关闭自动切换,需手动开启;一主两备默认开启。
|
7月前
|
数据采集 机器学习/深度学习 数据挖掘
利用Beautiful Soup和Pandas进行网页数据抓取与清洗处理实战
本文通过一个实战案例,介绍如何使用Python中的Beautiful Soup库抓取网页数据,并用Pandas进行清洗和处理。首先,确保安装了requests、beautifulsoup4和pandas库。接着,通过requests获取HTML内容,使用Beautiful Soup解析并提取新闻标题、发布时间和正文。然后,利用Pandas对数据进行清洗,包括去除多余空格、替换特殊字符、删除无效数据等。最后,根据需求进行数据处理(如过滤关键词)并保存为CSV或Excel文件。这个案例适合初学者和有一定经验的用户,帮助快速掌握这两个强大的工具。
215 3
|
7月前
|
机器学习/深度学习 编解码 人工智能
《深度解析:自注意力卷积神经网络的原理与卓越优势》
自注意力卷积神经网络融合了自注意力机制和卷积神经网络的优势,通过在特征图上动态分配注意力权重,捕捉长距离依赖关系。它不仅提升了局部特征提取能力,还能更好地理解全局结构与语义信息,在图像识别、自然语言处理等任务中表现出色。此外,该模型计算效率高、灵活性强、适应性广,并且易于扩展与其他技术结合,具有广泛的应用前景。
207 9
|
10月前
|
机器学习/深度学习 人工智能 算法
视频生成模型变身智能体:斯坦福Percy Liang等提出VideoAgent,竟能自我优化
斯坦福大学Percy Liang团队推出VideoAgent,一种能生成高质量视频并自我优化的模型。它结合强化学习和监督学习,根据用户反馈和环境变化自动调整,提升视频生成质量和用户体验,但同时也面临模型不稳定性和高资源需求等挑战。
220 6
|
10月前
|
存储 边缘计算 物联网
探索边缘计算:重塑物联网时代的数据处理格局
探索边缘计算:重塑物联网时代的数据处理格局
|
11月前
|
存储
硬盘碎片整理的原理是什么?
硬盘碎片整理的原理是什么?
416 4