数据结构与算法 基础 3

简介: 数据结构与算法 基础

树的基本定义

树是由 n ( n>=1 )个有限结点组成一个具有层次关系的集合。把它叫做 “ 树 ”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的

二叉树

结点的度: 一个结点含有的子树的个数称为该结点的度;

二叉树就是度不超过 2 的树 ( 每个结点最多有两个子结点 )


二叉树的节点类代码:

private class Node<Key,Value>{
    //存储键
    public Key key;
    //存储值
    private Value value;
    //记录左子结点
    public Node left;
    //记录右子结点
    public Node right;
    public Node(Key key, Value value, Node left, Node right) {
        this.key = key;
        this.value = value;
        this.left = left;
        this.right = right;
    }
}

满二叉树

一个二叉树,如果每一个层的结点树都达到最大值,则这个二叉树就是满二叉树。

完全二叉树

叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

二叉树的遍历

前序遍历:先访问根结点,然后再访问左子树,最后访问右子树

中序遍历:先访问左子树,中间访问根节点,最后访问右子树

后序遍历:先访问左子树,再访问右子树,最后访问根节点

如果我们分别对下面的树使用三种遍历方式进行遍历,得到的结果如下:

前序遍历代码:

//使用前序遍历,获取整个树中的所有键
public Queue<Key> preErgodic(){
    Queue<Key> keys = new Queue<>();
    preErgodic(root,keys);
    return keys;
}
//使用前序遍历,把指定树x中的所有键放入到keys队列中
private void preErgodic(Node x,Queue<Key> keys){
    if (x==null){
        return;
    }
    //1.把当前结点的key放入到队列中;
    keys.enqueue(x.key);
    //2.找到当前结点的左子树,如果不为空,递归遍历左子树
    if (x.left!=null){
        preErgodic(x.left,keys);
    }
    //3.找到当前结点的右子树,如果不为空,递归遍历右子树
    if (x.right!=null){
        preErgodic(x.right,keys);
    }
}


中序遍历代码:

//使用中序遍历,获取整个树中的所有键
public Queue<Key> midErgodic(){
    Queue<Key> keys = new Queue<>();
    midErgodic(root,keys);
    return keys;
}
//使用中序遍历,把指定树x中的所有键放入到keys队列中
private void midErgodic(Node x,Queue<Key> keys){
    if (x==null){
        return;
    }
    //1.找到当前结点的左子树,如果不为空,递归遍历左子树
    if (x.left!=null){
        midErgodic(x.left,keys);
    }
    //2.把当前结点的key放入到队列中;
    keys.enqueue(x.key);
    //3.找到当前结点的右子树,如果不为空,递归遍历右子树
    if (x.right!=null){
        midErgodic(x.right,keys);
    }
}

后序遍历代码:

//使用后序遍历,获取整个树中的所有键
public Queue<Key> afterErgodic(){
    Queue<Key> keys = new Queue<>();
    afterErgodic(root,keys);
    return keys;
}
//使用后序遍历,把指定树x中的所有键放入到keys队列中
private void afterErgodic(Node x,Queue<Key> keys){
    if (x==null){
        return;
    }
    //1.找到当前结点的左子树,如果不为空,递归遍历左子树
    if (x.left!=null){
        afterErgodic(x.left,keys);
    }
    //2.找到当前结点的右子树,如果不为空,递归遍历右子树
    if (x.right!=null){
        afterErgodic(x.right,keys);
    }
    //3.把当前结点的key放入到队列中;
    keys.enqueue(x.key);
}


堆的定义

堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组对象

堆的特性

1.它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。

2.它通常用数组来实现。具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子 结点则分别在位置4,5,6和7,以此类推。

如果一个结点的位置为k,则它的父结点的位置为[k/2],而它的两个子结点的位置则分别为2k和2k+1。这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或2k+1。

3.每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟我们之前学习的二叉查找树是有区别的。

堆排序

堆可以分为大根堆,小根堆


大根堆:每个节点的值都大于或者等于他的左右孩子节点的值

小根堆:每个结点的值都小于或等于其左孩子和右孩子结点的值0


堆是用数组完成数据元素的存储的,由于数组的底层是一串连续的内存地址,所以我们要往堆中插入数据,我们只能往数组中从索引0处开始,依次往后存放数据,但是堆中对元素的顺序是有要求的,每一个结点的数据要大于等于它的两个子结点的数据,所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候我们就需要通过一些方法让刚才插入的这个数据放入到合适的位置。

以大根堆的调整为例:

同样,删除元素也需要进行堆调整:


对于大根堆,索引1处的元素,也就是根结点是最大的元素,当我们把根结点的元素删除后,需要有一个新的根结点出现,这时我们可以暂时把堆中最后一个元素放到索引1处,充当根结点,但是它不满足大根堆的有序性需求,这个时候我们就需要通过一些方法,让这个新的根结点放入到合适的位置。

堆排序实现步骤(使用大根堆,实现从小到大排序):

  1. 构造大根堆;
  2. 得到堆顶元素,这个值就是最大值;
  3. 交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;
  4. 对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;
  5. 重复2~4这个步骤,直到堆中剩一个元素为止;
public class HeapSort {
  public static void main(String[] args) {
    int[] a=new int[]{5,32,4,23,1,8,64,67,35,85,12,123,543,45,23,10};
    System.out.println(Arrays.toString(a));
    int l=a.length;
    for(int i=0;i<a.length-1;i++)
    {
      for(int p=l-1;p>=0;p--)
      {
        sort(a,p,l);
      }
      int temp=a[0];
      a[0]=a[l-1];
      a[l-1]=temp;
      l--;
    }
    System.out.println(Arrays.toString(a));
  }
  public static void sort(int[] a,int p,int l)
  {
    int c=2*p+1;
    if(c<l)
    {
      int rc=c+1;
      if(rc<l && a[c]<a[rc]) c=rc;
      if(a[p]<a[c])
      {
        int temp=a[p];
        a[p]=a[c];
        a[c]=temp;
        p=c;
        sort(a,p,l);
      }
    }
  }
}
目录
相关文章
|
缓存 JavaScript 前端开发
带你读《现代Javascript高级教程》二、执行上下文与闭包(3)
带你读《现代Javascript高级教程》二、执行上下文与闭包(3)
226 0
猴子吃桃
猴子吃桃。
170 1
|
存储 缓存 安全
Python教程:深入理解 Python 字典(Dict)
Python 中的字典(Dictionary)是一种非常重要的数据结构,它提供了灵活的键值对存储方式,适用于各种实际编程场景。本文将带领您探索 Python 字典的全貌,从基础概念到高级应用,让您全面了解并熟练运用 Python 字典。
405 3
|
搜索推荐 测试技术
性能场景之业务模型中二八原则的误区
【2月更文挑战第18天】性能场景之业务模型中二八原则的误区
303 6
性能场景之业务模型中二八原则的误区
|
定位技术
简直完美!百度文库付费文档可以免费下载了!
hello,大家好,我是Jackpop,感谢您对平凡而诗意的关注。 今天,来跟大家聊一下百度文库。 我感觉百度文库是一个经久不衰的话题,蕴含着大量有价值的内容,尤其是对在校学生、教师等人员,非常有价值。
简直完美!百度文库付费文档可以免费下载了!
|
存储 Linux C++
【C++】Vector -- 详解(上)
【C++】Vector -- 详解(上)
|
弹性计算 Linux 开发工具
阿里云学生服务器申请流程与学生认证条件详解
阿里云学生服务器优惠活动:高效计划,可以免费领取一台阿里云服务器,如果你是一名高校学生,想搭建一个linux学习环境、git代码托管服务器,或者创建个人博客网站记录自己的学习成长历程,拥有一台云服务器是很有必要的。阿里云的飞天加速计划3.0——高校计划,面向学生开发者提供免费的云服务器福利,通过学生身份认证及续费任务后,最多可领取7个月免费云服务器ECS资源
793 0
阿里云学生服务器申请流程与学生认证条件详解
|
Java 程序员 网络安全
Flink处理函数实战之三:KeyedProcessFunction类
通过实战学习和了解处理函数的KeyedProcessFunction类
810 0
Flink处理函数实战之三:KeyedProcessFunction类
|
NoSQL Java Redis
Spring Boot使用Redis进行消息的发布与订阅
Redis 不仅提供一个NoSQL数据库,同时还提供了一套消息系统。 下面我将Spring Boot使用Redis进行消息的发布与订阅具体的流程分享给大家 首先引入依赖 org.
2396 0
|
存储 自然语言处理 关系型数据库
第08章 索引的创建与设计原则【2.索引及调优篇】【MySQL高级】1
第08章 索引的创建与设计原则【2.索引及调优篇】【MySQL高级】1
140 0