AOJ本の読書メモ   AOJ    次のAOJの問題へ    前のAOJの問題へ

ALDS1_8_C: Binary Search Tree III


問題へのリンク


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

// Q029 二分探索木:削除 https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_8_C&lang=jp
class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("18");
            WillReturn.Add("insert 8");
            WillReturn.Add("insert 2");
            WillReturn.Add("insert 3");
            WillReturn.Add("insert 7");
            WillReturn.Add("insert 22");
            WillReturn.Add("insert 1");
            WillReturn.Add("find 1");
            WillReturn.Add("find 2");
            WillReturn.Add("find 3");
            WillReturn.Add("find 4");
            WillReturn.Add("find 5");
            WillReturn.Add("find 6");
            WillReturn.Add("find 7");
            WillReturn.Add("find 8");
            WillReturn.Add("print");
            WillReturn.Add("delete 3");
            WillReturn.Add("delete 7");
            WillReturn.Add("print");
            //yes
            //yes
            //yes
            //no
            //no
            //no
            //yes
            //yes
            // 1 2 3 7 8 22
            // 8 2 1 3 7 22
            // 1 2 8 22
            // 8 2 1 22
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    struct NodeInfo
    {
        internal int? ParentNode;
        internal int? LeftNode;
        internal int? RightNode;
    }

    static int? mRootNode = null;
    static Dictionary<int?, NodeInfo> mTreeDict = new Dictionary<int?, NodeInfo>();

    static void Main()
    {
        List<string> InputList = GetInputList();

        foreach (string EachStr in InputList.Skip(1)) {
            string[] SplitArr = EachStr.Split(' ');

            if (SplitArr[0] == "insert") {
                Insert(int.Parse(SplitArr[1]));
            }
            if (SplitArr[0] == "find") {
                int? FindResult = Find(int.Parse(SplitArr[1]));
                Console.WriteLine(FindResult == null ? "no" : "yes");
            }
            if (SplitArr[0] == "delete") {
                Delete(int.Parse(SplitArr[1]));
            }
            if (SplitArr[0] == "print") {
                var InorderNodeList = new List<int?>();
                Inorder(mRootNode, InorderNodeList);
                foreach (int? EachInt in InorderNodeList) {
                    Console.Write(" {0}", EachInt);
                }
                Console.WriteLine();

                var PreorderNodeList = new List<int?>();
                Preorder(mRootNode, PreorderNodeList);
                foreach (int? EachInt in PreorderNodeList) {
                    Console.Write(" {0}", EachInt);
                }
                Console.WriteLine();
            }
        }
    }

    // Insert処理
    static void Insert(int? pZ)
    {
        int? ParentNode = null; // 親ノード
        int? CurrNode = mRootNode;
        while (CurrNode != null) {
            ParentNode = CurrNode; // 親ノードを設定
            if (pZ < CurrNode) {
                CurrNode = mTreeDict[CurrNode].LeftNode; // 左ノードへ移動
            }
            else {
                CurrNode = mTreeDict[CurrNode].RightNode; // 右ノードへ移動
            }
        }
        NodeInfo WillAdd;
        WillAdd.ParentNode = ParentNode;
        WillAdd.LeftNode = null;
        WillAdd.RightNode = null;
        mTreeDict[pZ] = WillAdd;

        if (ParentNode == null) { // T が空の場合
            mRootNode = pZ;
        }
        else if (pZ < ParentNode) {
            NodeInfo wkTreeDict = mTreeDict[ParentNode];
            wkTreeDict.LeftNode = pZ;
            mTreeDict[ParentNode] = wkTreeDict;
        }
        else {
            NodeInfo wkTreeDict = mTreeDict[ParentNode];
            wkTreeDict.RightNode = pZ;
            mTreeDict[ParentNode] = wkTreeDict;
        }
    }

    // Delete処理
    static void Delete(int? pZ)
    {
        // ノードが存在しない場合
        if (mTreeDict.ContainsKey(pZ) == false) return;

        // Zの子ノード数で場合分け
        var ChildNodeList = new List<int?>();
        if (mTreeDict[pZ].LeftNode != null) ChildNodeList.Add(mTreeDict[pZ].LeftNode);
        if (mTreeDict[pZ].RightNode != null) ChildNodeList.Add(mTreeDict[pZ].RightNode);

        // 子ノード数が0の場合
        if (ChildNodeList.Count == 0) {
            int? ParentNode = mTreeDict[pZ].ParentNode;
            if (ParentNode != null) { // 親ノードがある場合
                if (mTreeDict[ParentNode].LeftNode == pZ) {
                    NodeInfo wkTreeDict = mTreeDict[ParentNode];
                    wkTreeDict.LeftNode = null;
                    mTreeDict[ParentNode] = wkTreeDict;
                }
                else {
                    NodeInfo wkTreeDict = mTreeDict[ParentNode];
                    wkTreeDict.RightNode = null;
                    mTreeDict[ParentNode] = wkTreeDict;
                }
            }
            // 親ノードがない場合は、ルートノードなので変更しておく
            else {
                mRootNode = null;
            }
            mTreeDict.Remove(pZ);
        }

        // 子ノード数が1の場合
        if (ChildNodeList.Count == 1) {
            int? ParentNode = mTreeDict[pZ].ParentNode;
            if (ParentNode != null) { // 親ノードがある場合
                if (mTreeDict[ParentNode].LeftNode == pZ) {
                    NodeInfo wkTreeDict1 = mTreeDict[ParentNode];
                    wkTreeDict1.LeftNode = ChildNodeList[0];
                    mTreeDict[ParentNode] = wkTreeDict1;
                }
                else {
                    NodeInfo wkTreeDict1 = mTreeDict[ParentNode];
                    wkTreeDict1.RightNode = ChildNodeList[0];
                    mTreeDict[ParentNode] = wkTreeDict1;
                }
                NodeInfo wkTreeDict2 = mTreeDict[ChildNodeList[0]];
                wkTreeDict2.ParentNode = ParentNode;
                mTreeDict[ChildNodeList[0]] = wkTreeDict2;
            }
            // 親ノードがない場合は、ルートノードなので変更しておく
            else {
                mRootNode = ChildNodeList[0];
            }
            mTreeDict.Remove(pZ);
        }

        // 子ノード数が2の場合
        if (ChildNodeList.Count == 2) {
            // 次接点を求めて、削除
            int? Successor = DeriveSuccessor(ChildNodeList[1]);
            NodeInfo SuccessorInfo = mTreeDict[Successor];
            Delete(Successor);

            int? ParentNode = mTreeDict[pZ].ParentNode;
            if (ParentNode != null) { // 親ノードがある場合
                if (mTreeDict[ParentNode].LeftNode == pZ) {
                    NodeInfo wkTreeDict1 = mTreeDict[ParentNode];
                    wkTreeDict1.LeftNode = Successor;
                    mTreeDict[ParentNode] = wkTreeDict1;
                }
                else {
                    NodeInfo wkTreeDict1 = mTreeDict[ParentNode];
                    wkTreeDict1.RightNode = Successor;
                    mTreeDict[ParentNode] = wkTreeDict1;
                }
            }
            // 親ノードがない場合は、ルートノードなので変更しておく
            else {
                mRootNode = Successor;
            }
            mTreeDict.Remove(pZ);

            // 次接点ノードの追加
            SuccessorInfo.ParentNode = ParentNode;
            SuccessorInfo.LeftNode = ChildNodeList[0];
            SuccessorInfo.RightNode = ChildNodeList[1];
            if (SuccessorInfo.RightNode == Successor) {
                SuccessorInfo.RightNode = null;
            }
            mTreeDict[Successor] = SuccessorInfo;
        }
    }

    // 次節点を返す
    static int? DeriveSuccessor(int? pStartNode)
    {
        int? WillReturn = pStartNode;
        while (mTreeDict[WillReturn].LeftNode != null) {
            WillReturn = mTreeDict[WillReturn].LeftNode;
        }
        return WillReturn;
    }

    // 中間順巡回でDFS
    static void Inorder(int? pCurrNode, List<int?> pPrintNodeList)
    {
        if (pCurrNode == null) return;
        Inorder(mTreeDict[pCurrNode].LeftNode, pPrintNodeList);
        pPrintNodeList.Add(pCurrNode);
        Inorder(mTreeDict[pCurrNode].RightNode, pPrintNodeList);
    }

    // 先行順巡回でDFS
    static void Preorder(int? pCurrNode, List<int?> pPrintNodeList)
    {
        if (pCurrNode == null) return;
        pPrintNodeList.Add(pCurrNode);
        Preorder(mTreeDict[pCurrNode].LeftNode, pPrintNodeList);
        Preorder(mTreeDict[pCurrNode].RightNode, pPrintNodeList);
    }

    static int? Find(int? SearchVal)
    {
        int? CurrNode = mRootNode;
        while (CurrNode != null && CurrNode != SearchVal) {
            if (SearchVal < CurrNode) {
                CurrNode = mTreeDict[CurrNode].LeftNode;
            }
            else {
                CurrNode = mTreeDict[CurrNode].RightNode;
            }
        }
        return CurrNode;
    }
}


解説

Dictionaryで二分探索木を管理し、
再帰で、中間順巡回と先行順巡回で深さ優先探索してます。