二叉樹鏈表C++實現


結點的構造

源代碼:https://github.com/cjy513203427/C_Program_Base/tree/master/57.%E4%BA%8C%E5%8F%89%E6%A0%91%E9%93%BE%E8%A1%A8%E5%AE%9E%E7%8E%B0

#pragma once
#ifndef NODE_H
#define NODE_H

class Node
{
public:
    Node();
    Node *SearchNode(int nodeIndex);
    void DeleteNode();
    void PreorderTraversal();
    void InorderTraversal();
    void PostorderTraversal();

    int index;
    int data;
    Node *pLChild;
    Node *pRChild;
    Node *pParent;
};

#endif // !NODE_H

需要實現的方法

#pragma once
#ifndef  TREE_H
#define TREE_H
#include"Node.h"
class Tree
{
public:
    Tree();//創建樹
    ~Tree();//銷毀樹
    Node *SearchNode(int nodeIndex);//搜索結點
    bool AddNode(int nodeIndex, int direction, Node* pNode);//添加結點
    bool DeleteNode(int nodeIndex, Node* pNode);//刪除結點
    void PreorderTraversal();//前序遍歷
    void InorderTraversal();//中序遍歷
    void PostorderTraversal();//后序遍歷
private:
    Node * m_pRoot;
};

#endif // ! TREE_H

創建樹

申請一段內存

Tree::Tree()
{
    m_pRoot = new Node();
};

創建結點

Node::Node()
{
    index = 0;
    data = 0;
    pLChild = NULL;
    pRChild = NULL;
    pParent = NULL;
}

 

銷毀樹

調用Node的DeleteNode方法

Tree::~Tree()
{
    m_pRoot->DeleteNode();
}

如果當前Node對象(this)的pLChild不為空,遞歸調用DeleteNode方法,this->pLChild變成了新的this,直到delete this銷毀掉

如果當前Node對象(this)的pRChild不為空,遞歸調用DeleteNode方法,this->pRChild變成了新的this,直到delete this銷毀掉

如果當前Node對象(this)的pParent不為空,如果父節點的左子節點等於當前Node對象,將當前結點置空

如果當前Node對象(this)的pParent不為空,如果父節點的右子節點等於當前Node對象,將當前結點置空

思路:指定索引向下搜索從最底層子節點開始刪除,再往上回到指定索引並刪除,刪除的順序是后序

 

 

void Node::DeleteNode()
{
    if (this->pLChild != NULL)
    {
        this->pLChild->DeleteNode();
    }
    if (this->pRChild != NULL)
    {
        this->pRChild->DeleteNode();
    }
    if (this->pParent != NULL)
    {
        if (this->pParent->pLChild == this)
        {
            this->pParent->pLChild = NULL;
        }
        if (this->pParent->pRChild == this)
        {
            this->pParent->pRChild = NULL;
        }
    }
    
    delete this;
}

搜索結點

傳入索引,調用Node的SearchNode方法

Node *Tree::SearchNode(int nodeIndex)
{
    return m_pRoot->SearchNode(nodeIndex);
}

Node的SearchNode()

如果索引和傳入索引相等,返回當前Node對象

當this對象的左子節點不為空,當左子節點索引等於傳入索引,返回當前對象的子節點

否則繼續對當前對象的左子節點搜索,搜索結果賦值給temp,當temp不為空,返回temp

對右子節點的邏輯同上

否則返回為空

思路:從上向下搜索,順序為前序

Node *Node::SearchNode(int nodeIndex)
{
    if (this->index == nodeIndex)
    {
        return this;
    }

    Node *temp = NULL;
    if (this->pLChild != NULL)
    {
        if (this->pLChild->index == nodeIndex)
        {
            return this->pLChild;
        }
        else
        {
            temp = this->pLChild->SearchNode(nodeIndex);
            if (temp != NULL)
            {
                return temp;
            }
        }
    }

    if (this->pRChild != NULL)
    {
        if (this->pRChild->index == nodeIndex)
        {
            return this->pRChild;
        }
        else
        {
            temp = this->pRChild->SearchNode(nodeIndex);
            if (temp != NULL)
            {
                return temp;
            }
        }
    }

    return NULL;
}

添加結點

傳入索引,direction=0添加左子節點,direction=1添加右子節點,傳入pNode參數

先搜索結點並保存在temp中,temp為空返回錯誤

申請內存給node,為空返回錯誤

將pNode的index和data分別賦值給node的index和data

node的pParent指針指向temp,temp為指定索引的父節點

direction=0,將temp的pLChild指針指向node

direction=1,將temp的pRChild指針指向node

bool Tree::AddNode(int nodeIndex, int direction, Node* pNode)
{
    Node *temp = SearchNode(nodeIndex);
    if (temp == NULL)
    {
        return false;
    }

    Node *node = new Node();
    if (node == NULL)
    {
        return false;
    }
    node->index = pNode->index;
    node->data = pNode->data;
    node->pParent = temp;

    if (direction == 0)
    {
        temp->pLChild = node;
    }

    if (direction == 1)
    {
        temp->pRChild = node;
    }

    return true;
}

刪除結點

傳入nodeIndex,pNode參數

搜索結點保存在temp

temp為空,返回錯誤

pNode不為空,將的temp的data賦值給pNode的data,做返回值使用

調用Node的DeleteNode方法,參見銷毀樹

bool Tree::DeleteNode(int nodeIndex, Node* pNode)
{
    Node *temp = SearchNode(nodeIndex);
    if (temp == NULL)
    {
        return false;
    }

    if (pNode != NULL)
    {
        pNode->data = temp->data;
    }

    temp->DeleteNode();
    return true;
}

前序遍歷

調用了Node的PreorderTraversal()

void Tree::PreorderTraversal()
{
    m_pRoot->PreorderTraversal();
}

 

 Node的PreorderTraversal()

先輸出根節點

左子結點不為空遞歸,輸入當前結點

右子節點不為空遞歸,輸入當前結點

遞歸的算法最好對着源碼打斷點,就能看懂了

void Node::PreorderTraversal()
{
    cout << this->index<<"  "<<this->data << endl;
    if (this->pLChild != NULL)
    {
        this->pLChild->PreorderTraversal();
    }
    if (this->pRChild != NULL)
    {
        this->pRChild->PreorderTraversal();
    }
}

中序遍歷和后序遍歷

中序遍歷:左根右

后序遍歷:左右根

void Tree::InorderTraversal()
{
    m_pRoot->InorderTraversal();
}

void Tree::PostorderTraversal()
{
    m_pRoot->PostorderTraversal();
}

 

邏輯與前序遍歷代碼相似

this->index和this->data就是根節點的內容

左右結點進行遞歸

void Node::InorderTraversal()
{
    if (this->pLChild != NULL)
    {
        this->pLChild->InorderTraversal();
    }
    cout << this->index << "  " << this->data << endl;
    if (this->pRChild != NULL)
    {
        this->pRChild->InorderTraversal();
    }
}

void Node::PostorderTraversal()
{
    if (this->pLChild != NULL)
    {
        this->pLChild->PostorderTraversal();
    }
    if (this->pRChild != NULL)
    {
        this->pRChild->PostorderTraversal();
    }
    cout << this->index << "  " << this->data << endl;
}

補充

根據前序和中序推斷出二叉的結構

前序遍歷為ABDEGCFH

后序遍歷為DBGEACHF

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM