展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 如何使用Java实现线索化二叉树数据结构?

如何使用Java实现线索化二叉树数据结构?

1.线索化二叉树的介绍将数列{1,3,6,8,10,14}构建成一颗二叉树.问题分析:1.当我们对上面的二叉树进行中序遍历时,数列为{8,3,10,1,6,14}2.但是6,8,10,14这几个节点的左右指针,并没有完全的利用上.3.如果我们希望充分的利用各个节点的左右指针,让各个节点可以指向自己的前后节点,怎么办?4.解决方案-线索二叉树概念:当用二叉链表作为二叉树的存储结构时,可以很方便的找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点。所以使用线索化,利用二叉

本文目录

    1.线索化二叉树的介绍

    将数列 {1, 3, 6, 8, 10, 14 } 构建成一颗二叉树.

    如何使用Java实现线索化二叉树数据结构?

    问题分析:

    1.当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 }

    2.但是 6, 8, 10, 14 这几个节点的 左右指针,并没有完全的利用上.

    3.如果我们希望充分的利用 各个节点的左右指针, 让各个节点可以指向自己的前后节点,怎么办?

    4.解决方案-线索二叉树

    概念:当用二叉链表作为二叉树的存储结构时,可以很方便的找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点。所以使用线索化,利用二叉树结构链表的空指针域进行线索化。

    2.线索化二叉树的基本特点

    n 个结点的二叉链表中含有 n+1 【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")

    这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种

    3.线索化二叉树的应用案例

    中序线索化二叉树并遍历

    应用案例说明:将下面的二叉树,进行中序线索二叉树。中序遍历的数列为 {8, 3, 10, 1, 14, 6}

    如何使用Java实现线索化二叉树数据结构?

    思路分析

    中序遍历的结果:{8, 3, 10, 1, 14, 6}

    如何使用Java实现线索化二叉树数据结构?

    那么线索化之后的二叉树的左右指针如上图↑

    说明: 当线索化二叉树后,Node 节点的 属性 left 和 right ,有如下情况:

    • left 指向的是左子树,也可能是指向的前驱节点. 比如 ① 节点 left 指向的左子树, 而 ⑩ 节点的 left 指向的 就是前驱节点.

    • right 指向的是右子树,也可能是指向后继节点,比如 ① 节点 right 指向的是右子树,而⑩ 节点的 right 指向的是后继节点.

    因此要改变原来的二叉树的结点结构

    package com.studySelf.tree.threadedBinaryTree;
    
    /**
     * @author wang
     * @version 1.0
     * @packageName com.studySelf.tree.tree01
     * @className Node
     * @date 2022/4/19 20:15
     * @Description Node结点
     */
    public class Node {
        //唯一编号
        private int num;
        //结点的值
        private String name;
        //左结点
        private Node left;
        //右节点
        private Node right;
    
        //这个属性用来控制线索二叉树的结点的指向,0代表指向左结点,1代表指向前趋结点
        private int leftType;
        //这个属性用来控制线索二叉树的结点的指向,0代表指向右结点,1代表指向后继结点
        private int rightType;
    
    
        //构造方法
    
        public Node(int num, String name) {
            this.num = num;
            this.name = name;
        }
    
        public int getLeftType() {
            return leftType;
        }
    
        public void setLeftType(int leftType) {
            this.leftType = leftType;
        }
    
        public int getRightType() {
            return rightType;
        }
    
        public void setRightType(int rightType) {
            this.rightType = rightType;
        }
    
        public int getNum() {
            return num;
        }
    
        public void setNum(int num) {
            this.num = num;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Node getLeft() {
            return left;
        }
    
        public void setLeft(Node left) {
            this.left = left;
        }
    
        public Node getRight() {
            return right;
        }
    
        public void setRight(Node right) {
            this.right = right;
        }
    
        @Override
        public String toString() {
            return "Node{" +
                    "num=" + num +
                    ", name='" + name +
                    '}';
        }
    
        /**
         * 前序遍历
         */
        public void preSelect() {
            //首先输出根结点
            System.out.println(this);
            //其次判断是否有左结点
            if (this.left != null) {
                //没有左结点,就递归调用本方法输出该结点。
                this.left.preSelect();
            }
            if (this.right != null) {
                this.right.preSelect();
            }
        }
    
        /**
         * 中序遍历
         */
        public void infixSelect() {
            //首先判断左结点
            if (this.left != null) {
                //如果左结点不为空,递归向左子树调用
                this.left.infixSelect();
            }
            //当左结点为空,再输出根结点。当他本身就是最后一个左结点的时候,会直接输出,且没有右节点
            System.out.println(this);
            if (this.right != null) {
                //右节点同样如此,递归调用。直到没有结点为止。
                this.right.infixSelect();
            }
        }
    
        /**
         * 设二叉树有三个结点,根结点,左结点,右节点。
         * 后序遍历,解释,当一个二叉树的左结点不为空,那么他会进入下一个递归调用自己的后序遍历方法
         * 此时,根结点就是左结点,这时判断左结点,右节点均为空,就会输出左结点
         * 回退到根结点为this的时候,左结点已经判断完毕,接下来是右节点,右节点不为空,进入后续遍历递归,
         * 此时的this就是右节点,进入递归后,判断,不存在左右结点,输出this,也就是整个二叉树的右节点
         * 回退到this为根结点时,右节点也已经输出,走到最后一步,输出自己也就是this。
         * 整个后序遍历就结束,那么该二叉树的遍历结果就是左,右,根
         */
    
        public void afterSelect() {
            if (this.left != null) {
                this.left.afterSelect();
            }
    
            if (this.right != null) {
                this.right.afterSelect();
            }
            System.out.println(this);
        }
    
        /**
         * @param num
         * @Date 2022/4/21 17:51
         * @Param
         * @Return Node
         * @MetodName preSearchByNum
         * @Author wang
         * @Description 根据结点的编号来查询结点, 前序遍历查询,根,左,右
         */
        public Node preSearchByNum(int num) {
            //首先判断传进来的num与该结点的num是否相等
            //如果相等,那该结点就是我们要找的结点。
            if (this.num == num) {
                return this;
            }
    
            //如果不相等,该结点就不是我们要找的结点
            //那么我们就遍历该结点的左子节点,和右子结点
            //定义一个结点用于接收最后的返回结果
            Node resultNode = null;
            //如果该结点的左子结点不为空,就递归调用前序遍历,继续查找,如果找到了,那么resultNode就是我们想要的值
            if (this.left != null) {
                resultNode = this.left.preSearchByNum(num);
            }
    
            //如果遍历完左子结点,已经找到了我们想要的结果,直接返回结果即可,
            if (resultNode != null) {
                return resultNode;
            }
    
            //如果左子结点为空,且没有找到我们想要的结点的情况下。那就判断右子结点
            if (this.right != null) {
                resultNode = this.right.preSearchByNum(num);
            }
            //最后,如果找到了,那么resultNode一定会被赋值,如果没找到,就会返回null
            return resultNode;
        }
    
        /**
         * @param num
         * @Date 2022/4/21 17:58
         * @Param
         * @Return Node
         * @MetodName infixSearchByNum
         * @Author wang
         * @Description 中序遍历查找,左,根,右进行查询即可。
         */
        public Node infixSearchByNum(int num) {
            //首先判断左子结点,如果存在左子结点,递归继续查询遍历即可即可。
            Node resultNode = null;
            if (this.left != null) {
                resultNode = this.left.infixSearchByNum(num);
            }
    
            //如果左子结点已经找到了我们想要的结点,直接返回当前结点即可
            if (resultNode != null) {
                return resultNode;
            }
    
            //判断根结点
            if (this.num == num) {
                return this;
            }
    
            //判断右子结点,
            if (this.right != null) {
                resultNode = this.right.infixSearchByNum(num);
            }
            //最后返回我们的结果即可。
            return resultNode;
        }
    
    
        /**
         * @param num
         * @Date 2022/4/21 19:15
         * @Param
         * @Return Node
         * @MetodName afterSearchNum
         * @Author wang
         * @Description 后续遍历结点进行查找结点。左,右,根
         */
        public Node afterSearchNum(int num) {
            Node resultNode = null;
            //首先遍历左结点
            if (this.left != null) {
                resultNode = this.left.afterSearchNum(num);
            }
    
            //判断左结点是否找到哦啊
            if (resultNode != null) {
                return resultNode;
            }
    
            //判断右节点是否为空
            if (this.right != null) {
                resultNode = this.right.afterSearchNum(num);
            }
    
            //判断右节点是否找到
            if (resultNode != null) {
                return resultNode;
            }
    
            //判断根结点是否为我们找的结点
            if (this.num == num) {
                return this;
            }
            //最后返回
            return resultNode;
        }
    
        /**
         * @param num
         * @Date 2022/4/25 19:30
         * @Param
         * @Return void
         * @MetodName delNodeByNum
         * @Author wang
         * @Description 根据结点的编号删除结点
         */
        public void delNodeByNum(int num) {
            //首先,判断当前结点的左结点是否为空,并且左结点的num是否与num相等
            if (this.left != null && this.left.num == num) {
                //如果相等,那就说明该结点就是我们要删除的结点,将其左结点置空即可
                this.left = null;
                return;
            }
    
            //如果左结点没有执行,说明左结点没有我们想要的结果,也就是要删除的结点不在左结点
            //那么就对右节点进行判断
            if (this.right != null && this.right.num == num) {
                this.right = null;
                return;
            }
    
            //如果左右结点均没有找到目标结点
            //那么就对左子树进行递归删除操作
            if (this.left != null) {
                this.left.delNodeByNum(num);
            }
    
            //同理,如果左子树没有目标结点,向右子树进行递归删除操作
            if (this.right != null) {
                this.right.delNodeByNum(num);
            }
    
        }
    }

    可以看到我们多出来了这么两个属性:

        //这个属性用来控制线索二叉树的结点的指向,0代表指向左结点,1代表指向前趋结点
        private int leftType;
        //这个属性用来控制线索二叉树的结点的指向,0代表指向右结点,1代表指向后继结点
        private int rightType;

    中序线索化二叉树

      /**中序线索化二叉树*/
        /**
         * @param node 该结点为根结点,从根节点开始线索化二叉树,中序
         */
        public void infixThreadNodes(Node node) {
            /**首先判断二叉树的根节点上会否为空,如果根结点为空,不可以线索化,因为没有二叉树*/
            if (node == null) {
                return;
            }
    
            /**接着对左子树进行线索化*/
            infixThreadNodes(node.getLeft());
    
            /**对当前结点进行线索化*/
            /**首先判断当前结点的左子结点是否为空*/
            if (node.getLeft() == null) {
                //如果左子结点为空,说明就找到了我们需要线索化的结点
                //就可以将pre也就是一直在当前结点的前趋结点设置给当前结点的左子结点,
                //如果这是第一个结点,那么pre为空,正好第一个结点的前趋结点也为空
                node.setLeft(pre);
                //并且将它的左子结点的类型设置为前趋结点。1代表前趋结点
                node.setLeftType(1);
            }
    
            /**接着判断前趋结点的右子结点是否为空,前提是前趋结点不能为空,如果他为空,说明这是第一个结点还没走完*/
            if (pre != null && pre.getRight() == null) {
                //如果条件满足,说明前趋结点现在已经走到了值,并且还没有线索到后继结点,
                // 也就是当前结点的上一个结点(这个上一个结点就是当前的前趋结点)还没有后继,
                //那么上一个结点的后继结点就是当前结点,因此赋值前趋结点(也就是上一个结点)的后继结点为当前结点。
                //这样这条线索就连接上了,并且只有满足叶子结点的结点才可以进行线索化
                pre.setRight(node);
                pre.setRightType(1);
            }
    
            //当前两步走完之后,就可以将pre结点赋值为当前结点,
            // 因为下一个结点一走,当前结点就是前趋结点了。直到走到全部线索化结束
            //这步十分重要,这一步不写,整个线索化就连接不上
            pre = node;
    
            /**对右子树进行线索化*/
            infixThreadNodes(node.getRight());
        }

    中序线索化二叉树思路

    1. 因为中序遍历的二叉树顺序是左根右,因此,首先对左子树进行线索化,递归线索化即可;

    2. 当递归到左子树的最左结点的时候,他的左结点肯定为空,那么就对他的左结点赋值为pre(pre结点是在线索化的最后一步赋值为当前结点,这样递归才能进行下去),注意左结点的类型一定要改为1,代表他是前趋结点。前趋结点就线索掉了。

    3. 后继结点的处理则是判断前趋结点,当前趋结点不为空,并且前趋结点的右节点为空,那么设置前趋结点的右节点为当前结点,也就是上一个结点未设置的右节点,类型同样要设置为后继

    4. 最后就是对pre这个结点赋值,为当前结点,因为下一次递归,当前结点就成了上一个结点,也就是这里的pre

    5. 最后就是对二叉树的右子结点进行线索化。

    中序线索化二叉树的遍历

    1. 遍历中序线索化二叉树首先应该明确的是他的遍历顺序要和遍历原来的中序二叉树遍历的结果是一样的,才是遍历成功

    2. 那么第一步应该就是判断根结点不为空,也就是循环结束条件

    3. 接着就循环查找当前结点的左子结点类型为0的也就是没有被线索化的结点,只要他为0,那么结点就一直往左子结点赋值。直到找到第一个被线索化的结点,输出他,他就是我们第一个线索化并且也是中序遍历的第一个左子结点。

    4. 输出之后,判断他的右子结点是否被线索化,如果被线索化,那么当前结点node就被赋值为它自己的右子结点,并且输出,如果他之后的结点的右子结点的类型又为1,那么继续往后走并赋值,说明他有后继

    5. 直到右子结点的类型为0,退出循环之后,也应该向右再赋值,继续向后遍历

    代码演示

        /**遍历中序线索化二叉树*/
        public void infixThreadNodesSelect() {
            /**第一个结点为根结点*/
            Node node = root;
            while(node != null) {
                /**当结点不为空,就一直遍历*/
                /**当该结点的左子结点的类型为1的时候,也就是说该结点是被线索化的结点,
                 * 因为是中序遍历,所以应该遍历到最左边的最左子结点,那么就是第一个
                 * 左子结点类型为1的结点。*/
                while(node.getLeftType() == 0) {
                    node = node.getLeft();
                }
                /**当左子结点的类型为1,输出左子结点*/
                System.out.println(node);
    
                /**当右子结点类型为1,当前结点输出完毕后
                 * 中序遍历就应该输出右子结点,那么就是当前结点的右子结点类型只要为1,就往后移动
                 * 并且输出,当他为0,说明没有线索化,那么没有后继结点,但是他有右子结点,
                 * 因此要在循环结束以后向后移动。*/
                while (node.getRightType() == 1) {
                    node = node.getRight();
                    System.out.println(node);
                }
                /**当右子结点循环退出,说明这里到了类型为0也就是后继结点*/
                node = node.getRight();
            }

    4.前序线索化二叉树、遍历

    线索化二叉树

     /**
         * 前序线索化二叉树
         */
        public void preThreadNodes(Node node) {
            /**首先判断当前节点是否为空*/
            if (node == null) {
                return;
            }
    
            /**如果是前序遍历,那么先对当前结点进行判断,当前结点的前趋结点的操作*/
            if (node.getLeft() == null) {
                node.setLeft(pre);
                node.setLeftType(1);
            }
    
            /**处理后继结点,定义的前趋结点不为空,说明他有值,就是已经存在了上一个结点的值,他的右子结点没有值的话,就可以
             * 给他赋予后继结点为当前结点,这里赋予的也就是上一个结点*/
            if (pre != null && pre.getRight() == null) {
                pre.setRight(node);
                pre.setRightType(1);
            }
    
            /**这里是关键的一步*/
            pre = node;
    
            /**对左子结点进行线索化,注意,这里需要排除已经被线索化掉的结点,因为这里要考虑一个情况,
             * 比如这里已将到了最下面一个左子结点,由于是前序遍历,遍历到左子结点,他的前趋结点在上面就设置了
             * 如果这里不判断左子结点的类型,那么就会进入递归,但是这个递归如果进去了,就是错误的递归,因为他传过去的结点
             * 是我们刚刚给他赋值的前趋结点,也就是根结点。会发生错误。因此得判断类型*/
            if (node.getLeftType() != 1) {
                preThreadNodes(node.getLeft());
            }
    
    
            /**对右子结点进行递归线索化*/
            if (node.getRightType() != 1) {
                preThreadNodes(node.getRight());
            }
        }

     遍历线索化二叉树

    /**
         * 前序遍历线索二叉树*/
        public void preThreadNodeSelect() {
            Node node = root;
            while(node !=null) {
                while(node.getLeftType() == 0) {
                    /**前序遍历为根左右,先输出根结点,因为他每次进来循环肯定是先到根结点,所以一进该循环
                     * 就要输出根结点,当他的lefttype=1循环结束,说明遇到了被线索化的地方了。*/
                    System.out.println(node);
                    /**再最左子结点进行遍历*/
                    node = node.getLeft();
                }
                /**上面的循环结束之后就应该输出当前结点,也就是那个序列化的结点
                 * 之后结点向右移动继续遍历*/
                System.out.println(node);
                node = node.getRight();
            }
      }

    图解

    如何使用Java实现线索化二叉树数据结构?

    5.后序线索化二叉树

    后续线索化二叉树

    /**
     * 后序线索化二叉树的方法
     */
    public void postThreadedBinaryTree(Node node) {
        /**首先判断结店不能为空*/
        if (node == null) {
            return;
        }
    
        /**先后续线索化左子结点*/
        postThreadedBinaryTree(node.getLeft());
        /**在后续线索化右子结点*/
        postThreadedBinaryTree(node.getRight());
    
        /**处理当前结点的前趋结点*/
        if (node.getLeft() == null) {
            node.setLeft(pre);
            node.setLeftType(1);
        }
    
        /**处理后继结点*/
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
    }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。