`
zhuozhuobeauty
  • 浏览: 18043 次
  • 性别: Icon_minigender_2
社区版块
存档分类
最新评论

春天我种下一棵二叉树,秋天就能收获很多很多二叉树~~~

    博客分类:
  • java
 
阅读更多

关于二叉树,概念神马的不提,我们主要来谈一下二叉树的创建,遍历,插入,删除等等一系列的操作。

一、创建与遍历

创建要根据用户输入的字符串来统计每个字母出现的次数,从而作为每个字母的权值,来构建二叉树。

在进入主函数前先定义了全局变量

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
  
  
public class newa {  
    
    
	private int[] array;
    private static List<Node> nodeList=null;  

 

主函数如下

 public static void main(String[] args) {  

    	// 实例化一个接受命令行输入信息的对象
		java.util.Scanner sc = new java.util.Scanner(System.in);
		System.out.println("请输入要统计的字符串:");
		// 获取输入的一行字符串
		String temp = sc.nextLine();
                newa tree=new newa();  
	
              //调用用来计算权值的方法	 
               tree.wayOne(temp);
	
    	        tree.createBinTree();  
          //递归与非递归实现前序遍历
        preOrder(nodeList.get(0));  
        System.out.println();  
        preOrderStack(nodeList.get(0));  
        System.out.println();  
        //递归与非递归实现中序遍历
        inOrder(nodeList.get(0));  
        System.out.println();  
        inOrderStack(nodeList.get(0));  
        System.out.println();  
        //递归与非递归实现后序遍历 
        postOrder(nodeList.get(0));  
        System.out.println();  
        postOrderStack(nodeList.get(0));  
        System.out.println();  
          
      
    }  

 接着就是一个又一个的方法

1、用于统计权值的方法,这是我们第一节课的练习,小伙伴们你们还记得吗?这就是每次统计后把相同的字母都删除的那个方法1,唯一不同在于要返回array的值,这样我们就得到了所有的权值

public int[] wayOne(String temp) {
		// 定义一个存储统计次数的数组
//		int[] array = new int[256];
		// 循环遍历字符串
		for (int i = 0; i < temp.length(); i++) {
			// 获取指定索引位置的字符
			char c = temp.charAt(i);
			// 将字符转换为对应的ascii
			int ascii = c;
			// 将对应的ascii位置的数组元素加1
			array[ascii]++;
		}

		// 输出
		for (int i = 0; i < array.length; i++) {
			// 如果统计个数部位0则输出
			if (array[i] != 0) {
				char c = (char) i;
				System.out.println("字符" + c + "出现的次数是" + array[i]);
			}
		}
		return array;
	}

 

 2.创建二叉树的方法

//利用既定数组创建二叉树
    public void createBinTree(){  
          //实例化一个节点类的队列,并将数组中的数字添加进去
        nodeList=new LinkedList<Node>();  
        for(int i=0,len=array.length;i<len;i++){  
            nodeList.add(new Node(array[i]));  
        }  
          
        int len=array.length;  
        int lastRootIndex=(len>>1)-1;  
        for(int i=lastRootIndex;i>=0;i--){  
            Node root=nodeList.get(i);  
            int leftIndex=i*2+1;  
            Node leftNode=nodeList.get(leftIndex);  
            root.setLeft(leftNode);  
            //最后的那个根节点一定是有左子树的,但右子树不一定
            int rightIndex=leftIndex+1;  
            if(rightIndex<=len-1){  
                Node rightNode=nodeList.get(rightIndex);  
                root.setRight(rightNode);  
            }  
              
        }  
    }  
  

 3.使用非递归的三种遍历

 //非递归先序遍历 
    public static void preOrderStack(Node root){  
          
        Stack<Node> stack=new Stack<Node>();  
        Node p=root;  
        if(p!=null){  
            stack.push(p);  
            while(!stack.isEmpty()){  
                p=stack.pop();  
                visit(p);  
                if(p.getRight()!=null)stack.push(p.getRight());  
                if(p.getLeft()!=null)stack.push(p.getLeft());  
            }  
        }  
    }  
    //非递归中序遍历 
    public static void inOrderStack(Node p){  
        Stack<Node> stack=new Stack<Node>();  
        while(p!=null||!stack.isEmpty()){  
            //push all LeftChild,when p has no LeftChild,that means it's root,it should be visited  
            while(p!=null){  
                stack.push(p);  
                p=p.getLeft();  
            }  
            if(!stack.isEmpty()){  
                p=stack.pop();  
                visit(p);  
                p=p.getRight();  
            }  
        }  
    }  
      
    //非递归后序遍历
    public static void postOrderStack(Node p){  
        Stack<Node> stack=new Stack<Node>();  
        Node q=p;//q是最后一个被访问的节点
        while(p!=null){  
            while(p.getLeft()!=null){  
                stack.push(p);  
                p=p.getLeft();  
            }  
            while(p!=null&&(p.getRight()==null||p.getRight()==q)){  
                visit(p);  
                q=p;  
                if(stack.isEmpty())return;  
                p=stack.pop();  
            }  
            stack.push(p);  
            p=p.getRight();  
        }  
    }  

 看到这里,小伙伴们又要问了,stack是个神马? stack.push(p);  又是神马?这到底是神马跟神马??好是环燥啊!这些东西非我原创,只是百度来跟大家分享一下下,查找了API发现:

类 Stack<E>,是java.util下的一个类,API如是说道,

public class Stack<E>extends Vector<E>

Stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 pushpop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到堆栈顶距离的 search 方法。

首次创建堆栈时,它不包含项。

又出现了Vector<E>...我禁不住也烦躁了,有兴趣的小伙伴自己去查找吧,现在来看看Stack中的各种方法

boolean empty()
          测试堆栈是否为空。
 E peek()
          查看堆栈顶部的对象,但不从堆栈中移除它。
 E pop()
          移除堆栈顶部的对象,并作为此函数的值返回该对象。
 E push(E item)
          把项压入堆栈顶部。
 int search(Object o)
          返回对象在堆栈中的位置,以 1 为基数。

看了这些以后,还是有种雾里开花水中望月的感觉,也许等我们以后接触了这个类之后就能掌握他了吧~

3、递归实现的三种遍历

 //递归前序遍历
    public static void preOrder(Node root){  
        if(root==null){return;}  
        System.out.print(root.getData()+" ");  
        preOrder(root.getLeft());  
        preOrder(root.getRight());  
    }  
    //递归中序遍历
    public static void inOrder(Node root){  
        if(root==null){return;}  
        inOrder(root.getLeft());  
        System.out.print(root.getData()+" ");  
        inOrder(root.getRight());  
    }  
    //递归后序遍历
    public static void postOrder(Node root){  
        if(root==null){return;}  
        postOrder(root.getLeft());  
        postOrder(root.getRight());  
        System.out.print(root.getData()+" ");  
    }  

 看了这三种递归实现的遍历,有对比上面的非递归算法,应了我上一篇总结的话,递归实在是灰常灰常有用的东东!!!

4、最后是节点类

//节点类
    private static class Node{  
        private Node left;  
        private Node right;  
        private int data;  
        Node(int iData){  
            data=iData;  
            left=null;  
            right=null;  
        }  
        public void setLeft(Node leftNode){  
            this.left=leftNode;  
        }  
        public void setRight(Node rightNode){  
            this.right=rightNode;  
        }  
        public Node getLeft(){  
            return left;  
        }  
        public Node getRight(){  
            return right;  
        }  
        public int getData(){  
            return data;  
        }  
          
    }  
      
}  

 5.关于删除

删除实在是个很深奥的问题,现在仅止于看懂。。。自己的还没有编出来~~先把汉化后大神的代码贴上来吧

// ---------------------------根据值删除----------------------------------
   public boolean delete(int key) // 根据值删除
      {                           // (assumes non-empty list)
      Node current = root;
      Node parent = root;
      boolean isLeftChild = true;

      while(current.iData != key)        // 寻找节点,不相等就一直找
         {
         parent = current;
         if(key < current.iData)         // 若值小于当前结点所存的值,向左转
            {
            isLeftChild = true;//标记自己是父节点的左子结点还是右子节点
            current = current.leftChild;
            }
         else                            // or go right?
            {
            isLeftChild = false;
            current = current.rightChild;
            }
         if(current == null)             // 到达左边线的最下端
            return false;                // 没找到返回false
         }  
//退出了while意味着找到了对应节点
      // 若没有子节点,则直接删除
      if(current.leftChild==null &&
                                   current.rightChild==null)
         {
         if(current == root)             //半段是否为根节点
            root = null;                 // 清空树
         else if(isLeftChild)
            parent.leftChild = null;     // disconnect
         else                            // from parent
            parent.rightChild = null;
         }

      // 若没有右边的子节点,则直接把左边的子节点赋给父节点的左节点或者右节点
      else if(current.rightChild==null)
         if(current == root)
            root = current.leftChild;
         else if(isLeftChild)
            parent.leftChild = current.leftChild;
         else
            parent.rightChild = current.leftChild;

      // 若没有左边的子节点,则直接把右边的子节点赋给父节点的左节点或者右节点
      else if(current.leftChild==null)
         if(current == root)
            root = current.rightChild;
         else if(isLeftChild)
            parent.leftChild = current.rightChild;
         else
            parent.rightChild = current.rightChild;

      else  // 有两个子节点则:
         {
         // get successor of node to delete (current)
         Node successor = getSuccessor(current);

         // connect parent of current to successor instead
         if(current == root)
            root = successor;
         else if(isLeftChild)
            parent.leftChild = successor;//用于调整位置的方法
         else
            parent.rightChild = successor;

         // connect successor to current's left child
         successor.leftChild = current.leftChild;
         }  // end else two children
      // (successor cannot have a left child)
      return true;                                // success
      }  // end delete()
// -------------------------------------------------------------
   // 返回被删除节点的子节点中的最大值
   // 从右边开始
   private Node getSuccessor(Node delNode)
      {
      Node successorParent = delNode;
      Node successor = delNode;
      Node current = delNode.rightChild;   // go to right child
      while(current != null)               // until no more
         {                                 // left children,
         successorParent = successor;
         successor = current;
         current = current.leftChild;      // go to left child
         }
                                           // if successor not
      if(successor != delNode.rightChild)  // right child,
         {                                 // make connections
         successorParent.leftChild = successor.rightChild;
         successor.rightChild = delNode.rightChild;
         }
      return successor;
      }

 

大神用了两个方法来实现,一个是删除掉节点,一个是在他的子节点中找到最大的那一个,用来替换他的位置,我还知道了这个代码来自于清华的数据结构课件~~清华计算机学院果然强大~拜倒个~

目前二叉树就是现在这个样子,删除等我完善~~

上面那个遍历跟创建看上去如此流畅完美的代码,但却报错了!!传说中的空指针异常!!就在

        for(int i=0,len=array.length;i<len;i++)

               tree.createBinTree(); 

这两行代码上!!修改中。。。

 

分享到:
评论

相关推荐

    复制一棵二叉树

    ### 知识点:复制一棵二叉树 #### 一、引言 在计算机科学领域,数据结构中的二叉树是一种常见的非线性数据结构,它由节点组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。复制二叉树是指创建一个与原...

    将已知数组元素构造一棵二叉树

    在IT领域,特别是数据结构和算法的学习中,二叉树是一种基本且重要的数据结构。它由节点(或称为顶点)组成,每个节点最多有两个子节点,通常分别称为左子节点和右子节点。二叉树的应用广泛,包括搜索、排序、表达式...

    二叉树的各种操作各种遍历,复制,求高度,判断是否为一棵完全二叉树以及计算用二叉树存储的表达式

    判断一棵二叉树是否为完全二叉树可以通过广度优先搜索来实现。 ```cpp bool IsCompleteBinaryTree(BiTree bt) { bool flag = false; // 标记是否已经遇到过空节点 SqQueue Q; InitQueue(Q); EnQueue(Q, bt); ...

    二叉树的建立与遍历

    1) 按先序序列建立一棵二叉树时,先构造根结点,再构造根的左子树,然后构造右子树;每棵子树又都是二叉树,所以构造一棵子树的过程与构造整棵二叉树的过程完全相同(采用递归形式直到叶子结点为止)。 2) 先序序列...

    设一棵二叉树以二叉链表表示,试编写有关二叉树的递归算法

    设一棵二叉树以二叉链表表示,试编写有关二叉树的递归算法

    数据结构二叉树算法源码

    二叉树算法源码~~~C++实现的~~数据结构运用,充分应用了二叉树的模板实现的~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 二叉树算法源码~~~C++实现的~~~数据结构运用~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~...

    求二叉树的深度

    采用先序法建立一棵二叉树,设计求该二叉树的深度,二叉树的数据域类型为字符型, 扩展二叉树的叶子结点用‘#’表示,要求可以求多棵二叉树的深度,当二叉树的深度为0时程序结束。

    唯一的确定一棵二叉树

    给定一个二叉树的前序和中序遍历序列,可以唯一地重建这棵树,这是因为这两种遍历方式提供了足够的信息来确定树的结构。 前序遍历的顺序是:根节点 -&gt; 左子树 -&gt; 右子树。中序遍历的顺序是:左子树 -&gt; 根节点 -&gt; 右...

    唯一地确定一棵二叉树

    ### 唯一地确定一棵二叉树:前序遍历与中序遍历...综上所述,通过前序遍历和中序遍历序列,我们不仅能够唯一确定一棵二叉树的结构,还能验证构建的准确性,这一过程充分展示了二叉树遍历的实用性和算法设计的精妙之处。

    二叉树的基本运算

    1. 按先序序列构造一棵二叉链表表示的二叉树T; 2. 对这棵二叉树进行遍历:先序、中序、后序以及层次遍历,分别输出结点的遍历序列; 3. 求二叉树的深度/结点数目/叶结点数目;(选做) 4. 将二叉树每个结点的左右子树...

    构造二叉树与遍历二叉树

    一个二叉树由零个或多个节点组成,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。这种结构使得二叉树能够非常有效地存储具有层级关系的数据。 #### 二、二叉树的节点定义 在给定的代码片段中,我们...

    由前序(后序)和中序确定一棵二叉树

    由给定的前序和中序或者给定的中序和后序确定一棵二叉树的算法

    二叉树的建立及遍历

    创建一棵二叉树,分别实现先序、中序和后序遍历一棵二叉树,计算二叉树结点个数等操作。 1.建立二叉树方法1 2.建立二叉树方法2 3.先序递归遍历二叉树 4.中序递归遍历二叉树 5.后序递归遍历二叉树 6.层次遍历...

    二叉树_二叉树遍历_

    1.二叉树的基本操作实现【问题描述】建立一棵二叉树,用递归方法实现二叉树的如下基本操作:(1)按先序序列构造一棵二叉链表表示的二叉树T;(2)对这棵二叉树进行遍历:先序、中序、后序以及层次遍历,分别输出...

    编写复制一棵二叉树的非递归算法

    在二叉树的算法设计中,复制一棵二叉树是一个常见的任务,这有助于在不改变原始树的情况下进行操作。本文将详细讲解如何编写一个非递归算法来复制一棵二叉树,以及如何根据前序和中序序列重建二叉树。 首先,我们来...

    根据后序二叉树序列构造二叉树_扩展二叉树

    在计算机科学领域,二叉树是一种基础的数据结构,它由结点构成,每个结点最多有两个子节点,分别称为左子节点和右子节点。在众多的二叉树操作中,根据后序遍历序列(也称为后序序列)来构造二叉树是一项常见的任务。...

    广义表形式建立二叉树,并按层次遍历该二叉树

    二叉树采用二叉链表结构表示。设计并实现如下算法:输入某棵二叉树的广义表形式,建立该二叉树,并按层次遍历该二叉树

Global site tag (gtag.js) - Google Analytics