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);                                //顯示結點數據
         }
    }

到此爲止,樹的基本數據結構就到此結束了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章