গাছের মধ্যে সমস্ত নোডের সমস্ত বংশধর তৈরি করার সর্বাধিক দক্ষ উপায়


9

আমি একটি গাছ নেওয়ার জন্য সবচেয়ে কার্যকরী অ্যালগরিদমের সন্ধান করছি (উভয় প্রান্তের তালিকা হিসাবে সঞ্চিত; বা পিতা-মাতা নোড থেকে শিশু নোডের তালিকায় ম্যাপিংয়ের তালিকা হিসাবে); এবং উত্পাদিত করুন, প্রতিটি নোডের জন্য, এটি থেকে নেমে আসা সমস্ত নোডের একটি তালিকা (পাতার স্তর এবং নন-পাতার স্তর)।

বাস্তবায়ন অবশ্যই স্কেলের কারণে পুনরুদ্ধারের পরিবর্তে লুপের মাধ্যমে হওয়া উচিত; এবং আদর্শভাবে ও (এন) হওয়া উচিত।

এই তাই প্রশ্নটি একটি গাছের মধ্যে একটি নোডের জন্য উত্তর সন্ধানের জন্য একটি প্রমিত যুক্তিসঙ্গত সুস্পষ্ট সমাধানকে কভার করে। তবে স্পষ্টতই, প্রতিটি গাছের নোডের অ্যালগরিদম পুনরাবৃত্তি করা অত্যন্ত অদক্ষ (আমার মাথার উপরে, O (NlogN) থেকে O (N ^ 2))।

গাছের গোড়া জানা যায়। গাছটি সম্পূর্ণ নির্বিচারে আকারের হয় (যেমন এন-ন্যারি নয়, কোনওভাবেই ভারসাম্য নয়, আকার বা রূপ নয়, অভিন্ন গভীরতা নয়) - কিছু নোডের 1-2 বাচ্চা হয়, কারও 30 কে বাচ্চা থাকে।

ব্যবহারিক স্তরে (যদিও এটি অ্যালগরিদমকে প্রভাবিত করা উচিত নয়) গাছে ~ 100K-200K নোড রয়েছে।


আপনি লুপ এবং স্ট্যাক ব্যবহার করে পুনরাবৃত্তি সিমুলেট করতে পারেন, এটি কি আপনার সমাধানের জন্য অনুমোদিত?
জর্জিও

@ জর্জিও - অবশ্যই এটিই আমি "পুনরুদ্ধারের পরিবর্তে লুপগুলির মাধ্যমে" বোঝানোর চেষ্টা করেছি।
ডিভিকে

উত্তর:


5

আপনি যদি প্রতিটি লিস্টকে আলাদা আলাদা কপি হিসাবে উত্পাদন করতে চান তবে আপনি সবচেয়ে খারাপ অবস্থায় n the 2 স্পেসের চেয়ে ভাল অর্জনের আশা করতে পারবেন না। আপনার যদি প্রতিটি তালিকার কেবল অ্যাকসেসের প্রয়োজন হয়:

আমি মূল থেকে শুরু করে গাছের একটি অর্ডার ট্রভার্সাল সম্পাদন করব:

http://en.wikipedia.org/wiki/Tree_traversal

তারপরে গাছের প্রতিটি নোডের জন্য তার সাবট্রিতে ন্যূনতম ইন-অর্ডার নম্বর এবং সর্বাধিক সৃজনশীল নম্বরটি সঞ্চয় করুন (এটি সহজেই পুনরাবৃত্তির মাধ্যমে রক্ষণাবেক্ষণ করা হয় - এবং আপনি যদি চান তবে স্ট্যাকের সাহায্যে এটি সিমুলেট করতে পারেন)।

এখন আপনি সমস্ত নোড দৈর্ঘ্যের একটি অ্যারেতে রেখেছেন যেখানে অর্ডার নম্বরের নোডটি আমি অবস্থানে আছি। তারপরে যখন আপনাকে নোড এক্সের জন্য তালিকাটি সন্ধান করতে হবে, আপনি এ [এক্স.মিন, এক্স.ম্যাক্স] এ দেখুন - নোট করুন যে এই ব্যবধানটি নোড এক্সকে অন্তর্ভুক্ত করবে, যা সহজেই স্থির করা যায়।

এই সমস্তগুলি ও (এন) সময়ে সম্পন্ন হয় এবং ও (এন) স্থান নেয়।

আশা করি এটা কাজে লাগবে.


2

অদক্ষ অংশটি গাছটিকে অতিক্রম করছে না, তবে নোডগুলির তালিকা তৈরি করছে। এটি তালিকা তৈরি করা বুদ্ধিমান বলে মনে হচ্ছে:

descendants[node] = []
for child in node.childs:
    descendants[node].push(child)
    for d in descendants[child]:
        descendants[node].push(d)

যেহেতু প্রতিটি বংশধর নোড প্রতিটি পিতামাতার তালিকায় অনুলিপি করা হয়, তাই আমরা ভারসাম্যযুক্ত গাছগুলির জন্য গড়ে গড়ে ও (এন লগ এন) জটিলতা এবং সত্যিকারের লিঙ্কযুক্ত তালের অবনমিত গাছগুলির জন্য ও (n²) সবচেয়ে খারাপ পরিস্থিতি সহ শেষ করি।

আমরা যদি তালিকাটি অলসভাবে গণনা করার কৌশলটি ব্যবহার করি তবে আপনাকে কোনও সেটআপ করার দরকার আছে কিনা তার উপর নির্ভর করে আমরা ও (এন) বা ও (1) এ যেতে পারি। ধরুন আমাদের একটি আছে child_iterator(node)যা আমাদের সেই নোডের বাচ্চা দেয়। এরপরে আমরা তুচ্ছভাবে এর descendant_iterator(node)মতো একটি সংজ্ঞা দিতে পারি :

def descendant_iterator(node):
  for child in child_iterator(node):
    yield from descendant_iterator(child)
  yield node

পুনরাবৃত্তিযোগ্য সমাধানটি আরও অনেক বেশি জড়িত, যেহেতু পুনরাবৃত্তকারী নিয়ন্ত্রণ প্রবাহ জটিল (করোটিনগুলি) is আমি আজ এই উত্তরটি পরে আপডেট করব।

যেহেতু একটি গাছের ট্র্যাভারসাল হ'ল ও (এন) এবং কোনও তালিকার পুনরাবৃত্তি একইরূপে রৈখিক, তাই এই কৌশলটি কোনওভাবে পরিশোধ না করা অবধি ব্যয়টিকে পুরোপুরি পিছনে ফেলে। উদাহরণস্বরূপ, প্রতিটি নোডের জন্য বংশধরদের তালিকা ছাপানোর ক্ষেত্রে ও (n²) সবচেয়ে খারাপ জটিলতা রয়েছে: সমস্ত নোডের উপরে আইট্রেট করা ও (এন) হয় এবং তাই প্রতিটি নোডের বংশধরের উপর পুনরাবৃত্তি হয়, সেগুলি তালিকায় সঞ্চিত আছে বা গণনা করা অ্যাডহক ।

অবশ্যই, যদি কাজ করার জন্য আপনার প্রকৃত সংগ্রহের প্রয়োজন হয় তবে এটি কাজ করবে না।


দুঃখিত, -1। এগ্রোলিথমের পুরো উদ্দেশ্যটি ডেটা প্রাক্কুট করা। অলস গণনা এমনকি অ্যালগো চালানোর কারণকে পুরোপুরি পরাস্ত করে।
ডিভি কে

2
@ ডিভিকে ঠিক আছে, আমি আপনার প্রয়োজনীয়তাগুলি ভুল বুঝেছি। ফলাফলের তালিকা দিয়ে আপনি কী করছেন? যদি তালিকাগুলি পূর্বাভাস দেওয়া একটি বাধা (তবে তালিকাগুলি ব্যবহার না করা) হয় তবে এটি নির্দেশ করবে যে আপনি সমষ্টিগত সমস্ত ডেটা ব্যবহার করছেন না এবং অলস গণনাটি তখন জয় win তবে আপনি যদি সমস্ত ডেটা ব্যবহার করেন তবে পূর্বনির্মাণের জন্য অ্যালগরিদম মূলত অপ্রাসঙ্গিক - ডেটা ব্যবহারের অ্যালগরিদমিক জটিলতা কমপক্ষে তালিকা তৈরির জটিলতার সমান করবে।
আমন

0

এই সংক্ষিপ্ত অ্যালগরিদমটি এটি করা উচিত, কোডটি একবার দেখুন public void TestTreeNodeChildrenListing()

অ্যালগরিদম আসলে গাছের নোডগুলি ক্রমানুসারে চলে এবং বর্তমান নোডের পিতামাতার তালিকা রাখে। আপনার প্রয়োজনীয়তা অনুসারে বর্তমান নোড প্রতিটি পিতামাতার নোডের একটি শিশু এটি প্রতিটি হিসাবে এটি প্রতিটি শিশু হিসাবে যুক্ত হয়।

চূড়ান্ত ফলাফল অভিধানে সংরক্ষণ করা হয়।

    [TestFixture]
    public class TreeNodeChildrenListing
    {
        private TreeNode _root;

        [SetUp]
        public void SetUp()
        {
            _root = new TreeNode("root");
            int rootCount = 0;
            for (int i = 0; i < 2; i++)
            {
                int iCount = 0;
                var iNode = new TreeNode("i:" + i);
                _root.Children.Add(iNode);
                rootCount++;
                for (int j = 0; j < 2; j++)
                {
                    int jCount = 0;
                    var jNode = new TreeNode(iNode.Value + "_j:" + j);
                    iCount++;
                    rootCount++;
                    iNode.Children.Add(jNode);
                    for (int k = 0; k < 2; k++)
                    {
                        var kNode = new TreeNode(jNode.Value + "_k:" + k);
                        jNode.Children.Add(kNode);
                        iCount++;
                        rootCount++;
                        jCount++;

                    }
                    jNode.Value += " ChildCount:" + jCount;
                }
                iNode.Value += " ChildCount:" + iCount;
            }
            _root.Value += " ChildCount:" + rootCount;
        }

        [Test]
        public void TestTreeNodeChildrenListing()
        {
            var iteration = new Stack<TreeNode>();
            var parents = new List<TreeNode>();
            var dic = new Dictionary<TreeNode, IList<TreeNode>>();

            TreeNode node = _root;
            while (node != null)
            {
                if (node.Children.Count > 0)
                {
                    if (!dic.ContainsKey(node))
                        dic.Add(node,new List<TreeNode>());

                    parents.Add(node);
                    foreach (var child in node.Children)
                    {
                        foreach (var parent in parents)
                        {
                            dic[parent].Add(child);
                        }
                        iteration.Push(child);
                    }
                }

                if (iteration.Count > 0)
                    node = iteration.Pop();
                else
                    node = null;

                bool removeParents = true;
                while (removeParents)
                {
                    var lastParent = parents[parents.Count - 1];
                    if (!lastParent.Children.Contains(node)
                        && node != _root && lastParent != _root)
                    {
                        parents.Remove(lastParent);
                    }
                    else
                    {
                        removeParents = false;
                    }
                }
            }
        }
    }

    internal class TreeNode
    {
        private IList<TreeNode> _children;
        public string Value { get; set; }

        public TreeNode(string value)
        {
            _children = new List<TreeNode>();
            Value = value;
        }

        public IList<TreeNode> Children
        {
            get { return _children; }
        }
    }
}

আমার কাছে এটি দেখতে ও (এন লগ এন) থেকে ও (এন) জটিলতার মতো দেখতে খুব ভাল লাগে এবং ডিভি কে তাদের প্রশ্নের সাথে যুক্ত উত্তরটির চেয়ে সামান্যতম উন্নতি করে। সুতরাং যদি এটি কোনও উন্নতি না হয় তবে এই প্রশ্নের উত্তরটি কীভাবে দেবে? এই উত্তরটি যুক্ত করে কেবলমাত্র মূল্য হ'ল নিষ্পাপ আলগোরিদমের পুনরাবৃত্তি প্রকাশ করে।
আমন

এটি ও (এন), যদি আপনি অ্যালগরিদমকে ঘনিষ্ঠভাবে দেখেন তবে এটি নোডগুলির উপরে একবারে পুনরাবৃত্তি করে। একই সাথে এটি একই সময়ে প্রতিটি প্যারেন্ট নোডের জন্য শিশু নোডের সংগ্রহ তৈরি করে।
লো ফ্লাইং পেলিকান

1
আপনি সমস্ত নোডের মধ্য দিয়ে লুপ করুন যা ও (এন)। তারপরে আপনি সমস্ত বাচ্চার মধ্য দিয়ে লুপ করুন, যা আমরা আপাতত উপেক্ষা করব (আসুন এটির কিছু ধ্রুবক কারণ বিবেচনা করুন)। তারপরে আপনি বর্তমান নোডের সমস্ত পিতামাতাকে লুপ করবেন। ভারসাম্যযুক্ত গাছের মধ্যে এটি ও (লগ এন) হয় তবে অধঃপতন ক্ষেত্রে যেখানে আমাদের গাছটি একটি লিঙ্কযুক্ত তালিকা, এটি ও (এন) হতে পারে। সুতরাং আমরা যদি তাদের পিতামাতার মাধ্যমে লুপিংয়ের ব্যয় সহ সমস্ত নোডের মধ্য দিয়ে লুপিংয়ের ব্যয়কে গুণিত করি তবে আমরা ও (এন লগ এন) থেকে ও (এন) সময় জটিলতা পাই। মাল্টিথ্রেডিং ব্যতীত "একই সাথে" নেই।
আমন

"একই সাথে" এর অর্থ এটি একই লুপে সংগ্রহ তৈরি করে এবং এর সাথে অন্য কোনও লুপ জড়িত থাকে না।
লো ফ্লাইং পেলিকান

0

সাধারণত, আপনি কেবল পুনরাবৃত্তির পদ্ধতির ব্যবহার করবেন, কারণ এটি আপনাকে কার্যকর করার ক্রমটি এমনভাবে ঘুরিয়ে আনতে দেয় যে আপনি পাতা থেকে শুরু করে পাতার সংখ্যাটি উপরের দিকে গণনা করতে পারবেন। যেহেতু, আপনাকে বর্তমান নোড আপডেট করতে আপনার পুনরাবৃত্ত কলের ফলাফলটি ব্যবহার করতে হবে, তাই লেজ পুনরাবৃত্ত সংস্করণ পেতে বিশেষ প্রচেষ্টা লাগবে। আপনি যদি সেই প্রচেষ্টা না নেন তবে অবশ্যই এই পদ্ধতির সাহায্যে আপনার বড় বড় গাছের জন্য স্ট্যাকটি বিস্ফোরণ হয়।

আমরা উপলব্ধি করেছিলাম যে মূল ধারণাটি হল পাতাগুলি থেকে শুরু করে লুপিং অর্ডারটি মূলের দিকে ফিরে যাওয়া, যে প্রাকৃতিক ধারণাটি মনে আসে তা হ'ল গাছে টোপোলজিকাল বাছাই করা। পাতার সংখ্যার যোগফলের জন্য নোডগুলির ফলাফলের ক্রমটি রৈখিকভাবে অতিক্রম করা যেতে পারে (ধরে নিলে আপনি নোডের একটি পাতা যাচাই করতে পারবেন O(1))। টপোলজিকাল সাজানোর সামগ্রিক সময়ের জটিলতা O(|V|+|E|)

আমি ধরে নিলাম যে আপনার Nনোডের সংখ্যা, যা |V|সাধারণত হবে (ডাগ নামকরণ থেকে) omen Eঅন্যদিকে আকার আপনার গাছের আর্টির উপর নির্ভর করে। উদাহরণস্বরূপ, একটি বাইনারি গাছের নোডে সর্বাধিক 2 প্রান্ত থাকে, সুতরাং O(|E|) = O(2*|V|) = O(|V|)সেই ক্ষেত্রে, যার ফলে সামগ্রিক O(|V|)অ্যালগোরিদম হতে পারে। মনে রাখবেন যে গাছের সামগ্রিক কাঠামোর কারণে আপনার মতো কিছু থাকতে পারে না O(|E|) = O(|V|^2)। প্রকৃতপক্ষে, যেহেতু প্রতিটি নোডের একটি অনন্য পিতামাতা থাকে, আপনি যখন কেবলমাত্র পিতা-মাতার সম্পর্ক বিবেচনা করেন তখন নোডের প্রতি গুনতে আপনার বেশিরভাগ এক প্রান্ত থাকতে পারে, তাই গাছের জন্য আমাদের গ্যারান্টি রয়েছে O(|E|) = O(|V|)। সুতরাং উপরের অ্যালগরিদম গাছের আকারে সর্বদা লিনিয়ার থাকে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.