【數據結構】70_二叉樹的經典面試題分析

面試題 一

單結點刪除
描述:編寫一個函數用於刪除二叉樹中的全部單度結點
要求:結點刪除後,其惟一的子結點替代它的位置

image.png

情形1:結點中包含指向父結點的指針

  • 定義功能:delOdd1(node)node

    • 刪除 node 爲根結點的二叉樹中的單度結點

image.png

編程實驗:單度結點的刪除

#include <iostream>
#include "BTreeNode.h"

using namespace std;
using namespace DTLib;

template < typename T >
BTreeNode<T>* createTree()
{
    static BTreeNode<int> ns[9];

    for(int i=0; i<9; i++)
    {
        ns[i].value = i;
        ns[i].parent = NULL;
        ns[i].left = NULL;
        ns[i].right = NULL;
    }

    ns[0].left = &ns[1];
    ns[0].right = &ns[2];
    ns[1].parent = &ns[0];
    ns[2].parent = &ns[0];

    ns[1].left = &ns[3];
    ns[1].right = NULL;
    ns[3].parent = &ns[1];

    ns[2].left = &ns[4];
    ns[2].right = &ns[5];
    ns[4].parent = &ns[2];
    ns[5].parent = &ns[2];

    ns[3].left = NULL;
    ns[3].right = &ns[6];
    ns[6].parent = &ns[3];

    ns[4].left = &ns[7];
    ns[4].right = NULL;
    ns[7].parent = &ns[4];

    ns[5].left = &ns[8];
    ns[5].right = NULL;
    ns[8].parent = &ns[5];

    return ns;
}

template < typename T >
void printInOrder(BTreeNode<T>* node)
{
    if( node != NULL )
    {
        printInOrder(node->left);

        cout << node->value <<" ";

        printInOrder(node->right);
    }
}

template < typename T >
void printDualList(BTreeNode<T>* node)
{
    BTreeNode<T>* g = node;

    cout << "head -> tail: " << endl;

    while( node != NULL )
    {
        cout << node->value << " ";

        g = node;

        node = node->right;
    }

    cout << endl;

    cout << "tail -> head: " << endl;

    while( g != NULL )
    {
        cout << g->value << " ";

        g = g->left;
    }

    cout << endl;
}

//----------------------------------------------------------------------
template <typename T>
BTreeNode<T>* delOdd1(BTreeNode<T> *node)
{
    BTreeNode<T> *ret = nullptr;

    if (node != nullptr)
    {
        if (((node->left != nullptr) && (node->right == nullptr)) ||
            ((node->left == nullptr) && (node->right != nullptr)))
        {
            BTreeNode<T> *parent = dynamic_cast<BTreeNode<T>*>(node->parent);
            BTreeNode<T> *child = (node->left != nullptr) ? node->left : node->right;

            if (parent != nullptr)
            {
                BTreeNode<T> *& parent_child = (parent->left == node) ? parent->left : parent->right;

                parent_child = child;
                child->parent = parent;
            }
            else
            {
                child->parent = nullptr;
            }

            if (node->flag())
            {
                delete node;
            }

            ret = delOdd1(child);
        }
        else
        {
            delOdd1(node->left);
            delOdd1(node->right);

            ret = node;
        }
    }

    return ret;
}

int main()
{
    BTreeNode<int>* ns = createTree<int>();

    printInOrder(ns);

    cout << endl;

    ns = delOdd1(ns);

    printInOrder(ns);

    return 0;
}

輸出:ios

3 6 1 0 7 4 2 8 5
6 0 7 2 8

情形2:結點中只包含左右孩子指針

  • 定義功能: delOdd2(node)面試

    • 刪除 node 爲根結點的二叉樹中的單度結點

image.png

編程實驗:單度結點刪除

#include <iostream>
#include "BTreeNode.h"

using namespace std;
using namespace DTLib;

template < typename T >
BTreeNode<T>* createTree()
{
    static BTreeNode<int> ns[9];

    for(int i=0; i<9; i++)
    {
        ns[i].value = i;
        ns[i].parent = NULL;
        ns[i].left = NULL;
        ns[i].right = NULL;
    }

    ns[0].left = &ns[1];
    ns[0].right = &ns[2];
    ns[1].parent = &ns[0];
    ns[2].parent = &ns[0];

    ns[1].left = &ns[3];
    ns[1].right = NULL;
    ns[3].parent = &ns[1];

    ns[2].left = &ns[4];
    ns[2].right = &ns[5];
    ns[4].parent = &ns[2];
    ns[5].parent = &ns[2];

    ns[3].left = NULL;
    ns[3].right = &ns[6];
    ns[6].parent = &ns[3];

    ns[4].left = &ns[7];
    ns[4].right = NULL;
    ns[7].parent = &ns[4];

    ns[5].left = &ns[8];
    ns[5].right = NULL;
    ns[8].parent = &ns[5];

    return ns;
}

template < typename T >
void printInOrder(BTreeNode<T>* node)
{
    if( node != NULL )
    {
        printInOrder(node->left);

        cout << node->value <<" ";

        printInOrder(node->right);
    }
}

template < typename T >
void printDualList(BTreeNode<T>* node)
{
    BTreeNode<T>* g = node;

    cout << "head -> tail: " << endl;

    while( node != NULL )
    {
        cout << node->value << " ";

        g = node;

        node = node->right;
    }

    cout << endl;

    cout << "tail -> head: " << endl;

    while( g != NULL )
    {
        cout << g->value << " ";

        g = g->left;
    }

    cout << endl;
}

//----------------------------------------------------------------------
template <typename T>
void delOdd2(BTreeNode<T> *&node)
{
    if (node != nullptr)
    {
        if (((node->left != nullptr) && (node->right == nullptr)) ||
            ((node->left == nullptr) && (node->right != nullptr)))
        {
            if (node->flag())
            {
                delete node;
            }

            node = (node->left != nullptr) ? node->left : node->right;

            delOdd2(node);
        }
        else
        {
            delOdd2(node->left);
            delOdd2(node->right);
        }
    }
}

int main()
{
    BTreeNode<int>* ns = createTree<int>();

    printInOrder(ns);

    cout << endl;

    delOdd2(ns);

    printInOrder(ns);

    return 0;
}

輸出:編程

3 6 1 0 7 4 2 8 5
6 0 7 2 8

面試題 二

中序線索化二叉樹
描述:編寫一個函數用於中序線索化二叉樹
要求:不容許使用其餘數據結構

image.png

解法一:在中序遍歷的同時進行線索化

思路

  • 使用輔助指針,在中序遍歷時指向當前結點的前驅結點
  • 訪問當前結點時,鏈接與前驅結點的前後次序

image.png

定義功能

  • inOrderThread(node, pre)數據結構

    • node : 根結點,也是中序訪問的結點
    • pre: 爲中序遍歷時的前驅結點指針

image.png

編程實驗:中序線索化

#include <iostream>
#include "BTreeNode.h"

using namespace std;
using namespace DTLib;

template < typename T >
BTreeNode<T>* createTree()
{
    static BTreeNode<int> ns[9];

    for(int i=0; i<9; i++)
    {
        ns[i].value = i;
        ns[i].parent = NULL;
        ns[i].left = NULL;
        ns[i].right = NULL;
    }

    ns[0].left = &ns[1];
    ns[0].right = &ns[2];
    ns[1].parent = &ns[0];
    ns[2].parent = &ns[0];

    ns[1].left = &ns[3];
    ns[1].right = NULL;
    ns[3].parent = &ns[1];

    ns[2].left = &ns[4];
    ns[2].right = &ns[5];
    ns[4].parent = &ns[2];
    ns[5].parent = &ns[2];

    ns[3].left = NULL;
    ns[3].right = &ns[6];
    ns[6].parent = &ns[3];

    ns[4].left = &ns[7];
    ns[4].right = NULL;
    ns[7].parent = &ns[4];

    ns[5].left = &ns[8];
    ns[5].right = NULL;
    ns[8].parent = &ns[5];

    return ns;
}

template < typename T >
void printInOrder(BTreeNode<T>* node)
{
    if( node != NULL )
    {
        printInOrder(node->left);

        cout << node->value <<" ";

        printInOrder(node->right);
    }
}

template < typename T >
void printDualList(BTreeNode<T>* node)
{
    BTreeNode<T>* g = node;

    cout << "head -> tail: " << endl;

    while( node != NULL )
    {
        cout << node->value << " ";

        g = node;

        node = node->right;
    }

    cout << endl;

    cout << "tail -> head: " << endl;

    while( g != NULL )
    {
        cout << g->value << " ";

        g = g->left;
    }

    cout << endl;
}

template <typename T>
void inOrderThread(BTreeNode<T> *node, BTreeNode<T> *&pre)
{
    if (node != nullptr)
    {
        inOrderThread(node->left, pre);

        node->left = pre;

        if (pre != nullptr)
        {
            pre->right = node;
        }

        pre = node;

        inOrderThread(node->right, pre);
    }
}

template <typename T>
BTreeNode<T> *inOrderThread(BTreeNode<T> *node)
{
    BTreeNode<T> * pre = nullptr;

    inOrderThread(node, pre);

    while ((node != nullptr) && (node->left != nullptr))
    {
        node = node->left;
    }

    return node;
}

int main()
{
    BTreeNode<int>* ns = createTree<int>();

    printInOrder(ns);

    cout << endl;

    ns = inOrderThread(ns);

    printDualList(ns);

    return 0;
}

輸出:函數

3 6 1 0 7 4 2 8 5
head -> tail:
3 6 1 0 7 4 2 8 5
tail -> head:
5 8 2 4 7 0 1 6 3

解法二:中序遍歷的結點次序正好是結點的水平次序

思路

  • 使用輔助指針,指向轉換後雙向鏈表的頭結點和尾結點
  • 根結點與左右子樹轉換的雙向鏈表鏈接,成爲完整雙向鏈表

image.png

定義功能

  • inOrderThread(node, head, tail)spa

    • node: 根結點,也是中序訪問的結點
    • head: 轉換成功後指向雙向鏈表的首結點
    • tail:轉換成功後指向雙向鏈表的尾結點

image.png

編程實驗:中序線索化

#include <iostream>
#include "BTreeNode.h"

using namespace std;
using namespace DTLib;

template < typename T >
BTreeNode<T>* createTree()
{
    static BTreeNode<int> ns[9];

    for(int i=0; i<9; i++)
    {
        ns[i].value = i;
        ns[i].parent = NULL;
        ns[i].left = NULL;
        ns[i].right = NULL;
    }

    ns[0].left = &ns[1];
    ns[0].right = &ns[2];
    ns[1].parent = &ns[0];
    ns[2].parent = &ns[0];

    ns[1].left = &ns[3];
    ns[1].right = NULL;
    ns[3].parent = &ns[1];

    ns[2].left = &ns[4];
    ns[2].right = &ns[5];
    ns[4].parent = &ns[2];
    ns[5].parent = &ns[2];

    ns[3].left = NULL;
    ns[3].right = &ns[6];
    ns[6].parent = &ns[3];

    ns[4].left = &ns[7];
    ns[4].right = NULL;
    ns[7].parent = &ns[4];

    ns[5].left = &ns[8];
    ns[5].right = NULL;
    ns[8].parent = &ns[5];

    return ns;
}

template < typename T >
void printInOrder(BTreeNode<T>* node)
{
    if( node != NULL )
    {
        printInOrder(node->left);

        cout << node->value <<" ";

        printInOrder(node->right);
    }
}

template < typename T >
void printDualList(BTreeNode<T>* node)
{
    BTreeNode<T>* g = node;

    cout << "head -> tail: " << endl;

    while( node != NULL )
    {
        cout << node->value << " ";

        g = node;

        node = node->right;
    }

    cout << endl;

    cout << "tail -> head: " << endl;

    while( g != NULL )
    {
        cout << g->value << " ";

        g = g->left;
    }

    cout << endl;
}

template <typename T>
void inOrderThread2(BTreeNode<T> *node, BTreeNode<T> *& head, BTreeNode<T> *&tail)
{
    if (node != nullptr)
    {
        BTreeNode<T> *h = nullptr;
        BTreeNode<T> *t = nullptr;

        inOrderThread2(node->left, h, t);

        node->left = t;

        if (t != nullptr)
        {
            t->right = node;
        }

        head = (h != nullptr) ? h : node;

        h = nullptr;
        t = nullptr;

        inOrderThread2(node->right, h, t);

        node->right = h;

        if (h != nullptr)
        {
            h->left = node;
        }

        tail = (t != nullptr) ? t : node;
    }
}

template <typename T>
BTreeNode<T> *inOrderThread2(BTreeNode<T> *node)
{
    BTreeNode<T> *head = nullptr;
    BTreeNode<T> *tail = nullptr;

    inOrderThread2(node, head, tail);

    return head;
}

int main()
{
    BTreeNode<int>* ns = createTree<int>();

    printInOrder(ns);

    cout << endl;

    ns = inOrderThread2(ns);

    printDualList(ns);

    return 0;
}

輸出:指針

3 6 1 0 7 4 2 8 5
head -> tail:
3 6 1 0 7 4 2 8 5
tail -> head:
5 8 2 4 7 0 1 6 3

以上內容整理於狄泰軟件學院系列課程,請你們保護原創!code

相關文章
相關標籤/搜索