java数据结构(四)——栈

树结构是一种描述非线性关系的数据结构。对于树的基本概念不想过多赘述,可以自行查阅相关资料,这里主要讲解一种简单的树结构——二叉树。二叉树是树的一种特殊形式,它有n个结点,每个结点最多有两个子结点。二叉树的子树仍然是二叉树,二叉树的两个子树分别是左子树和右子树,因此二叉树也是有序树。二叉树又分为:完全二叉树和满二叉树,概念不再详述,自行查找。
完全二叉树的性质:
1、如果m!=1,则结点m的父节点为m/2;
2、如果2*m<=n,则m的左子树编号为2*m;若2*m>n则无左子树,也无右子树。
3、如果2*m+1<=n,则m的右子树编号为2*m+1;若2*m+1>n则无右子树。
完全二叉树的深度为[log2n]+1。
二叉树的存储方式:1、顺序存储 2、链式存储。
顺序存储即按层将二叉树存储到一个数组中,这里不再详述,重点讲链式存储。
二叉树的链式存储:
1、数据部分

class CBTType               //定义二叉树结点类型 
{
    String data;                //元素数据
    CBTType left;               //左子树结点指针
    CBTType right;          //右子树结点指针
}

2、初始化二叉树

CBTType InitTree()                          //初始化二叉树的根 
    {
    CBTType node;

        if((node=new CBTType())!=null) //申请内存
        {
            System.out.printf("请先输入一个根结点数据:\n");
            node.data=input.next();
            node.left=null;
            node.right=null;
            if(node!=null)                  //如果二叉树根结点不为空 
            {
                return node;
            }
            else
            {
                return null;
            }
        }
        return null;
    }

3、添加结点

void AddTreeNode(CBTType treeNode)          //添加结点
    {
         CBTType pnode,parent;
         String data;
         int menusel;

        if((pnode=new CBTType())!=null) //分配内存
        {
            System.out.printf("输入二叉树结点数据:\n");

           pnode.data=input.next();
            pnode.left=null;                    //设置左右子树为空 
            pnode.right=null;

            System.out.printf("输入该结点的父结点数据:");
            data=input.next();

            parent=TreeFindNode(treeNode,data); //查找指定数据的结点 
            if(parent==null)                            //如果未找到
            {
                System.out.printf("未找到该父结点!\n");
                pnode=null;                     //释放创建的结点内存 
                return;
             }
             System.out.printf("1.添加该结点到左子树\n2.添加该结点到右子树\n");
             do
             {
                menusel=input.nextInt();                    //输入选择项

                if(menusel==1 || menusel==2)
                {
                    if(parent==null)
                    {
                        System.out.printf("不存在父结点,请先设置父结点!\n");
                    } 
                    else
                    {
                        switch(menusel)
                        {
                            case 1:             //添加到左结点 
                                if(parent.left!=null)   //左子树不为空 
                                {
                                    System.out.printf("左子树结点不为空!\n");
                                }
                                else
                                {
                                    parent.left=pnode;
                                }
                                break;
                            case 2:         //添加到右结点
                                if( parent.right!=null) //右子树不为空 
                                {
                                    System.out.printf("右子树结点不为空!\n"); 
                                }
                                else
                                {
                                    parent.right=pnode;
                                }
                                break;
                            default:
                                System.out.printf("无效参数!\n");
                        }
                    }
                }
             }while(menusel!=1 && menusel!=2);
        }
    }

4、查找结点

CBTType TreeFindNode(CBTType treeNode,String data) //查找结点
{
CBTType ptr;
if(treeNode==NULL)
{
   return NULL;
}
  else
  {
     if(treeNode.data.equals(data))
     {
        return treeNode;
     }
     else                                            //查找左右子树
     {  
        if((ptr=TreeFindNode(treeNode.left,data))!=NULL)
        {
            return ptr;
        }
        else if((ptr=TreeFindNode(treeNode.left,data))!=NULL)
        {
            return ptr;
        } 
        else
        {
            return null;
        }
     }
   }
}

5、获取左/右子树

CBTType TreeLeftNode(CBTType treeNode)  //获取左子树
    {
        if(treeNode!=null)
        {
            return treeNode.left;                   //返回值
        }
        else
        {
            return null;
        }
    }

    CBTType TreeRightNode(CBTType treeNode)     //获取右子树
    {
        if(treeNode!=null)
        {
            return treeNode.right;              //返回值
        }
        else
        {
            return null;
        }
    }

6、判断树是否为空 计算二叉树深度

int TreeIsEmpty(CBTType treeNode)           //判断空树
    {
        if(treeNode!=null)
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }

    int TreeDepth(CBTType treeNode)                 //计算二叉树深度
    {
    int depleft,depright;

        if(treeNode==null)
        {
            return 0; //对于空树,深度为0
        }
        else
        {
            depleft = TreeDepth(treeNode.left);         //左子树深度 (递归调用)
            depright = TreeDepth(treeNode.right);   //右子树深度 (递归调用)
            if(depleft>depright)
            {
               return depleft + 1; 
            }
            else
            {
                return depright + 1; 
            }
        } 
    }

7、清空二叉树 显示结点数据

void ClearTree(CBTType treeNode)        // 清空二叉树
    {
         if(treeNode!=null)
         {
             ClearTree(treeNode.left);      //清空左子树 
             ClearTree(treeNode.right);     //清空右子树 
             treeNode=null;                 //释放当前结点所占内存 
//           treeNode=null;
         }
    }

    void TreeNodeData(CBTType p)            //显示结点数据
    {
         System.out.printf("%s ",p.data);               //输出结点数据
    }

8、二叉树遍历算法
(1)按层遍历算法

void LevelTree(CBTType treeNode)    //按层遍历 
    {
         CBTType p;
         CBTType[] q=new CBTType[MAXLEN];                                       //定义一个顺序栈 
         int head=0,tail=0;

         if(treeNode!=null)                                             //如果队首指针不为空     
         {
             tail=(tail+1)%MAXLEN;                                  //计算循环队列队尾序号 
             q[tail] = treeNode;                                        //将二叉树根指针进队
         }
         while(head!=tail)                                          //队列不为空,进行循环 
         {
             head=(head+1)%MAXLEN;                              //计算循环队列的队首序号 
             p=q[head];                                             //获取队首元素 
             TreeNodeData(p);                                       //处理队首元素 
             if(p.left!=null)                                       //如果结点存在左子树
             {
                 tail=(tail+1)%MAXLEN;                              //计算循环队列的队尾序号 
                 q[tail]=p.left;                                        //将左子树指针进队 
             }

             if(p.right!=null)                                      //如果结点存在右子树 
             {
                 tail=(tail+1)%MAXLEN;                              //计算循环队列的队尾序号 
                 q[tail]=p.right;                                       //将右子树指针进队 
             }
         }
    }

(2)先序遍历

void DLRTree(CBTType treeNode)  //先序遍历 
    {     
         if(treeNode!=null) 
         {
             TreeNodeData(treeNode);                            //显示结点的数据 
             DLRTree(treeNode.left);
             DLRTree(treeNode.right);
         }
    }

(3)中序遍历

void LDRTree(CBTType treeNode)  //中序遍历 
    {
         if(treeNode!=null) 
         {
             LDRTree(treeNode.left);                    //中序遍历左子树
             TreeNodeData(treeNode);                                //显示结点数据 
             LDRTree(treeNode.right);               //中序遍历右子树
         }
    }

(4)后序遍历

void LRDTree(CBTType treeNode) //后序遍历
    {
         if(treeNode!=null)
         {
             LRDTree(treeNode.left);                    //后序遍历左子树 
             LRDTree(treeNode.right);               //后序遍历右子树
             TreeNodeData(treeNode);                                //显示结点数据
         }
    }

到此为止,树的基本数据结构就到此结束了!

猜你喜欢

转载自blog.csdn.net/h9f3d3/article/details/51756070