Java数据结构之线索化二叉树的实现

目录
  • 1.线索化二叉树的介绍
  • 2.线索化二叉树的基本特点
  • 3.线索化二叉树的应用案例
  • 4.前序线索化二叉树、遍历
  • 5.后序线索化二叉树

1.线索化二叉树的介绍

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

问题分析:

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}

思路分析

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

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

说明: 当线索化二叉树后,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();
        }
​​​​​​​  }

图解

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;
}

后续线索化思路类似,只不过将顺序改为了左右根。

以上就是Java数据结构之线索化二叉树的实现的详细内容,更多关于Java线索化二叉树的资料请关注我们其它相关文章!

(0)

相关推荐

  • 剑指Offer之Java算法习题精讲二叉树专项训练

    题目一  解法 /** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; *

  • JAVA二叉树的基本操作

    目录 记录二叉树的基本操作DEMO 1.创建一个二叉树类 2.然后创建二叉树的节点 记录二叉树的基本操作DEMO 1.创建一个二叉树类 这里约束了泛型只能为实现了Comparable这个接口的类型. /** * @author JackHui * @version BinaryTree.java, 2020年03月05日 12:45 */ public class BinaryTree<T extends Comparable> { //树根 BinaryTreeNode root; publ

  • Java 最优二叉树的哈夫曼算法的简单实现

    最优二叉树也称哈夫曼树,讲的直白点就是每个结点都带权值,我们让大的值离根近.小的值离根远,实现整体权值(带权路径长度)最小化. 哈夫曼算法的思想我认为就是上面讲的,而它的算法实现思路是这样的: 从根结点中抽出权值最小的两个(涉及排序,但是我这个实现代码没做严格的排序,只有比较)合并出新的根结点重新加入排序(被抽出来的两个自然是变成非根结点了啊),就这样循环下去,直到合并完成,我们得到一颗最优二叉树--哈夫曼树. 说明: (1)哈夫曼树有n个叶子结点,则我们可以推出其有n-1个分支结点.因此我在定

  • java数据结构之搜索二叉树

    本文实例为大家分享了java数据结构之搜索二叉树的具体代码,供大家参考,具体内容如下 搜索二叉树的定义是:在一个二叉树上,左节点一定比父节点小,右节点一定比父节点大,其他定义跟二叉树相同. 代码实现: public class node {     int data;     public node left, right=null;       public node(int data) {         this.data = data;       }       public node

  • 详解Java数据结构之平衡二叉树

    目录 什么是二叉搜索树 平衡二叉搜索树 平衡二叉搜索树建树程序 计算每个节点的高度 计算每个节点的平衡因子 合并二叉树 旋转调整函数 整体代码 什么是二叉搜索树 简单来说,就是方便搜索的二叉树,是一种具备特定结构的二叉树,即,对于节点n,其左子树的所有节点的值都小于等于其值,其右子树的所有节点的值都大于等于其值.​ 以序列2,4,1,3,5,10,9,8为例,如果以二叉搜索树建树的方式,我们建立出来的逐个步骤应该为 第一步: 第二步: 第三步: 第四步: 第五步: 第六步: 第七步: 第八步:

  • Java实现二叉树的示例代码(递归&迭代)

    目录 1.二叉树基本概念见上节:详解Java中二叉树的基础概念(递归&迭代) 2.本次展示链式存储 以此图为例,完整代码如下: //基础二叉树实现 //使用左右孩子表示法 import java.util.*; import java.util.Deque; public class myBinTree { private static class TreeNode{ char val; TreeNode left; TreeNode right; public TreeNode(char va

  • Java数据结构之线索化二叉树的实现

    目录 1.线索化二叉树的介绍 2.线索化二叉树的基本特点 3.线索化二叉树的应用案例 4.前序线索化二叉树.遍历 5.后序线索化二叉树 1.线索化二叉树的介绍 将数列 {1, 3, 6, 8, 10, 14 } 构建成一颗二叉树. 问题分析: 1.当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 } 2.但是 6, 8, 10, 14 这几个节点的 左右指针,并没有完全的利用上. 3.如果我们希望充分的利用 各个节点的左右指针, 让各个节点可以指向自己的前后节点

  • Java数据结构二叉树难点解析

    前言 本章,我们主要需要了解以下内容 什么是线索二叉树 怎么去把二叉树线索化 怎么通过线索二叉树查找某个数的后继结点 二叉树的查看--二叉树怎们遍历 什么是线索二叉树 首先我们来了解一下什么是线索二叉树? 定义:一个二叉树通过如下的方法"穿起来":所有原本为空的右(孩子)指针改为指向该节点在中序序列中的后继,所有原本为空的左(孩子)指针改为指向该节点的中序序列的前驱. 再看一下为什么要有线索二叉树? 顾名思义,线索二叉树,肯定是根据线索查找,查找速度肯定更快. 线索二叉树能线性地遍历二

  • 数据结构与算法中二叉树子结构的详解

    数据结构与算法中二叉树子结构的详解 需求 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 树的描述: class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } 解决思路 使用了栈将元素入栈,并不断的弹出元素,弹出一个元素的时候,拼接成字符串,并用特殊符号进行区分,该方法

  • 常用的Java数据结构知识点汇总

    目录 1.数据结构分类 2.线性数据结构 2.1数组 2.2可变数组 2.3链表 2.4栈 2.5队列 3.非线性数据结构 3.1树 3.2图 3.3散列表 3.4堆 1. 数据结构分类 按照线性和非线性可以将Java数据结构分为两大类: ①线性数据结构:数组.链表.栈.队列②非线性数据结构:树.堆.散列表.图 2. 线性数据结构 2.1 数组 数组是一种将元素存储于连续内存空间的数据结构,并且要求元素的类型相同. // 定义一个数组长度为5的数组array int[] array = new

  • Java数据结构之稀疏数组的实现与应用

    目录 1.稀疏数组引入 1.1 使用场景 1.2 稀疏数组简介 2.稀疏数组的实现 2.1 案例概述 2.2 思路分析 2.3 代码实现 1.稀疏数组引入 1.1 使用场景 笔者在课程设计中曾写过一个扫雷小游戏,为了便于讲解,我们来做个简化(实际比这个复杂),只考虑当前位置有雷与无雷两种状况:雷用1表示,非雷用0表示.则将当前状态用二维数组表示如下: 在右侧的二维数组中,很多都是0,即记录了很多没有意义的数据,因此,我们考虑使用稀疏数组进行存储结构的优化. 1.2 稀疏数组简介 当一个数组中的大

  • Java数据结构之有效队列定义与用法示例

    本文实例讲述了Java数据结构之有效队列定义与用法.分享给大家供大家参考,具体如下: /** * @描述 有序对列 * 从任何位置插入数据都是有序的 * @项目名称 Java_DataStruct * @包名 com.java.stack * @类名 Queue * @author chenlin */ public class SequeQueue { private long[] arr; private int maxSize;// 最大空间 private int len;// 有效长度

  • Java数据结构之链表(动力节点之Java学院整理)

    单链表: insertFirst:在表头插入一个新的链接点,时间复杂度为O(1) deleteFirst:删除表头的链接点,时间复杂度为O(1) find:查找包含指定关键字的链接点,由于需要遍历查找,平均需要查找N/2次,即O(N) remove:删除包含指定关键字的链接点,由于需要遍历查找,平均需要查找N/2次,即O(N) public class LinkedList { private class Data{ private Object obj; private Data next =

  • java数据结构与算法之双向循环队列的数组实现方法

    本文实例讲述了java数据结构与算法之双向循环队列的数组实现方法.分享给大家供大家参考,具体如下: 需要说明的是此算法我并没有测试过,这里给出的相当于伪代码的算法思想,所以只能用来作为参考! package source; public class Deque { private int maxSize; private int left; private int right; private int nItems; private long[] myDeque; //constructor p

  • java数据结构与算法之快速排序详解

    本文实例讲述了java数据结构与算法之快速排序.分享给大家供大家参考,具体如下: 交换类排序的另一个方法,即快速排序. 快速排序:改变了冒泡排序中一次交换仅能消除一个逆序的局限性,是冒泡排序的一种改进:实现了一次交换可消除多个逆序.通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. 步骤: 1.从数列中挑出一个元素,称为 "基准"(piv

  • java数据结构排序算法之树形选择排序详解

    本文实例讲述了java数据结构排序算法之树形选择排序.分享给大家供大家参考,具体如下: 这里我们就来说说选择类排序之一的排序:树形选择排序 在简单选择排序中,每次的比较都没有用到上次比较的结果,所以比较操作的时间复杂度是O(N^2),想要降低比较的次数,则需要把比较过程中的大小关系保存下来.树形选择排序是对简单选择排序的改进. 树形选择排序:又称锦标赛排序(Tournament Sort),是一种按照锦标赛的思想进行选择排序的方法.首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进

随机推荐