计算Splay树中的总和范围

时间:2018-12-23 14:35:22

标签: c# tree sum range splay-tree

我需要使用八叉树计算距离总和。

我已经实现了Insert,Find,Remove和Splay方法,它们工作正常,但是我在计算树中给定范围的总和时遇到了麻烦。

注意:测试用例中的树很深,我不能使用递归解决方案。

这是我在C#中的树类实现:

public class Nodes
{
    public Nodes LeftChild { get; set; }
    public Nodes RightChild { get; set; }
    public Nodes Parent { get; set; }
    public int Key { get; set; }
    public bool IsLeftChild => Parent != null && Parent.LeftChild.Key == Key;

    public Nodes(int key = -1, Nodes left = null, Nodes right = null, Nodes parent = null)
    {
        this.LeftChild = left;
        this.RightChild = right;
        this.Parent = parent;
        this.Key = key;
    }
}

这是我的求和方法:

public Nodes Summation(Nodes current, int low, int high)
    {
        if (current == null) return current;
        if (low > high) return current;
        Nodes temp;
        temp = new Nodes(current);
        sumData = new List<int>();

        while (temp != null)
        {
            temp = Splay(temp, low);

            if (temp.Key < low)
                temp = temp.RightChild;
            else
                temp.LeftChild = null;

            temp = Splay(temp, high);

            if (temp.Key > high)
                temp = temp.LeftChild;
            else
                temp.RightChild = null;

            sumData.Add(temp.Key);
            if (temp.LeftChild != null)
            {
                temp.LeftChild.Parent = temp.Parent;
                temp = temp.LeftChild;
            }
            else
                break;
        }

        return current;
    }

问题在于这种方法中,我需要复制原始树,但无法复制,并且它总是更改原始树,因此树会被弄乱。

如果您能帮助解决此方法或帮助我实现更好的方法,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

我已经把整个树实现了。 在下面,我发布了整个代码,以便其他人可以使用它。

使用非递归方法在C#中实现Splay树:

using System;
using System.Collections.Generic;
using TestCommon;

namespace A11
{
    public class Nodes
    {
        public Nodes LeftChild { get; set; }
        public Nodes RightChild { get; set; }
        public Nodes Parent { get; set; }
        public long Key { get; set; }
        public bool IsLeftChild => Parent != null && Parent.LeftChild != null && Parent.LeftChild.Key == Key;

        public Nodes(long key = -1, Nodes left = null, Nodes right = null, Nodes parent = null)
        {
            this.LeftChild = left;
            this.RightChild = right;
            this.Parent = parent;
            this.Key = key;
        }
        public Nodes(Nodes Copy)
        {
            LeftChild = Copy.LeftChild;
            RightChild = Copy.RightChild;
            Parent = Copy.Parent;
            Key = Copy.Key;
        }
    }

    public class SetWithRageSums : Processor
    {
        public SetWithRageSums(string testDataName) : base(testDataName)
        {
            CommandDict =
                        new Dictionary<char, Func<string, string>>()
                        {
                            ['+'] = Add,
                            ['-'] = Del,
                            ['?'] = Find,
                            ['s'] = Sum
                        };
        }

        public override string Process(string inStr) =>
            TestTools.Process(inStr, (Func<string[], string[]>)Solve);

        public readonly Dictionary<char, Func<string, string>> CommandDict;

        protected const long M = 1_000_000_001;

        protected long X = 0;

        protected List<long> Data;

        protected List<long> sumData;

        protected Nodes root = null;

        public string[] Solve(string[] lines)
        {
            X = 0;
            Data = new List<long>();
            root = null;
            List<string> result = new List<string>();
            foreach (var line in lines)
            {
                char cmd = line[0];
                string args = line.Substring(1).Trim();
                var output = CommandDict[cmd](args);
                if (null != output)
                    result.Add(output);
            }
            return result.ToArray();
        }

        private long Convert(long i)
            => i = (i + X) % M;

        private string Add(string arg)
        {
            long i = Convert(long.Parse(arg));
            var x = Find(arg);
            if (x == "Found")
                return null;
            Insert(root, i);
            return null;
        }

        private string Del(string arg)
        {
            long i = Convert(long.Parse(arg));
            Nodes node = TravelDown(i);
            Delete(node);
            return null;
        }

        private string Find(string arg)
        {
            long i = Convert(int.Parse(arg));
            TravelDown(i);
            if (root == null) return "Not found";
            return root.Key == i ? "Found" : "Not found";
        }

        private string Sum(string arg)
        {
            var toks = arg.Split();
            long l = Convert(long.Parse(toks[0]));
            long r = Convert(long.Parse(toks[1]));
            long sum = 0;
            sum =  inorder(root,  l,  r);
            X = sum;
            return sum.ToString();
        }

        public Nodes TravelDown(long key)
        {
            Nodes PrevNode = null;
            Nodes z = root;
            while (z != null)
            {
                PrevNode = z;
                if (key > z.Key)
                    z = z.RightChild;
                else if (key < z.Key)
                    z = z.LeftChild;
                else if (key == z.Key)
                {
                    Splay(z);
                    return z;
                }

            }
            if (PrevNode != null)
            {
                Splay(PrevNode);
                return null;
            }
            return null;
        }

        private void Splay(Nodes x)
        {
            if (x == null)
                return;

            while (x.Parent != null)
            {
                Nodes Parent = x.Parent;
                Nodes GrandParent = Parent.Parent;
                if (GrandParent == null)
                {
                    if (x == Parent.LeftChild)
                        ZigR(x, Parent);
                    else
                        ZigL(x, Parent);
                }
                else
                {
                    if (x == Parent.LeftChild)
                    {
                        if (Parent == GrandParent.LeftChild)
                        {
                            ZigR(Parent, GrandParent);
                            ZigR(x, Parent);
                        }
                        else
                        {
                            ZigR(x, x.Parent);
                            ZigL(x, x.Parent);
                        }
                    }
                    else
                    {
                        if (Parent == GrandParent.LeftChild)
                        {
                            ZigL(x, x.Parent);
                            ZigR(x, x.Parent);
                        }
                        else
                        {
                            ZigL(Parent, GrandParent);
                            ZigL(x, Parent);
                        }
                    }
                }
            }
            root = x;
        }

        public void ZigR(Nodes c,Nodes p)
        {
            if ((c == null) || (p == null) || (p.LeftChild != c) || (c.Parent != p))
                return;

            if (p.Parent != null)
            {
                if (p == p.Parent.LeftChild)
                    p.Parent.LeftChild = c;
                else
                    p.Parent.RightChild = c;
            }
            if (c.RightChild != null)
                c.RightChild.Parent = p;

            c.Parent = p.Parent;
            p.Parent = c;
            p.LeftChild = c.RightChild;
            c.RightChild = p;
        }

        public void ZigL(Nodes c,Nodes p)
        {
            if ((c == null) || (p == null) || (p.RightChild != c) || (c.Parent != p))
                return;
            if (p.Parent != null)
            {
                if (p == p.Parent.LeftChild)
                    p.Parent.LeftChild = c;
                else
                    p.Parent.RightChild = c;
            }
            if (c.LeftChild != null)
                c.LeftChild.Parent = p;
            c.Parent = p.Parent;
            p.Parent = c;
            p.RightChild = c.LeftChild;
            c.LeftChild = p;
        }

        public void Insert(Nodes current, long key)
        {
            Nodes z = root;
            Nodes p = null;
            while (z != null)
            {
                p = z;
                if (key > p.Key)
                    z = z.RightChild;
                else
                    z = z.LeftChild;
            }
            z = new Nodes();
            z.Key = key;
            z.Parent = p;
            if (p == null)
                root = z;
            else if (key > p.Key)
                p.RightChild = z;
            else
                p.LeftChild = z;
            Splay(z);
        }

        public void Delete(Nodes node)
        {
            if (node == null)
                return;

            Splay(node);
            if ((node.LeftChild != null) && (node.RightChild != null))
            {
                Nodes min = node.LeftChild;
                while (min.RightChild != null)
                    min = min.RightChild;

                min.RightChild = node.RightChild;
                node.RightChild.Parent = min;
                node.LeftChild.Parent = null;
                root = node.LeftChild;
            }
            else if (node.RightChild != null)
            {
                node.RightChild.Parent = null;
                root = node.RightChild;
            }
            else if (node.LeftChild != null)
            {
                node.LeftChild.Parent = null;
                root = node.LeftChild;
            }
            else
            {
                root = null;
            }
            node.Parent = null;
            node.LeftChild = null;
            node.RightChild = null;
            node = null;
        }

        public long inorder(Nodes current,long low,long high)
        {
            Stack<Nodes> nodePile = new Stack<Nodes>();
            List<long> result = new List<long>();
            if (current == null)
                return 0;

            while (true)
            {
                nodePile.Push(current);
                if (current.LeftChild == null)
                    break;
                current = current.LeftChild;
            }

            while (true)
            {
                if (current.LeftChild == null && nodePile.Count != 0)
                {
                    result.Add(nodePile.Peek().Key);
                    if (nodePile.Peek().RightChild != null)
                        current = nodePile.Pop().RightChild;
                    else
                    {
                        nodePile.Pop();
                        continue;
                    }
                    while (true)
                    {
                        nodePile.Push(current);
                        if (current.LeftChild == null)
                            break;
                        current = current.LeftChild;
                    }
                }
                if (current.LeftChild == null && nodePile.Count == 0)
                {
                    long sum = 0;
                    for (int i = 0; i < result.Count; i++)
                    {
                        if (result[i] <= high && result[i] >= low)
                            sum += result[i];
                    }
                    return sum;
                }
            }
        }
    }
}

PS:我修改了一些部分大学课程的代码,因此您可以忽略部分代码。