লিঙ্কযুক্ত তালিকায় একটি লুপ কীভাবে সনাক্ত করবেন?


434

বলুন জাভাতে আপনার লিঙ্কযুক্ত তালিকার কাঠামো রয়েছে। এটি নোড দিয়ে তৈরি:

class Node {
    Node next;
    // some user data
}

এবং প্রতিটি নোড শেষ নোড ব্যতীত পরবর্তী নোডের দিকে নির্দেশ করে, যার পরের জন্য নাল থাকে। বলুন যে সম্ভাবনা রয়েছে যে তালিকার একটি লুপ থাকতে পারে - যেমন চূড়ান্ত নোড, শূন্যের পরিবর্তে, তালিকার আগে যে নোডের একটি রেফারেন্স রয়েছে।

লেখার সেরা উপায় কি

boolean hasLoop(Node first)

trueপ্রদত্ত নোড একটি লুপের সাথে তালিকার প্রথমটি এবং falseঅন্যথায় যদি কোনটি ফিরে আসে ? আপনি কীভাবে লিখতে পারেন যাতে স্থির পরিমাণ এবং সময় মতো যুক্তিসঙ্গত পরিমাণ লাগে?

লুপের সাথে তালিকার মতো দেখতে একটি চিত্র এখানে রয়েছে:

বিকল্প পাঠ


50
বাহ..আমি এই নিয়োগকর্তার পক্ষে কাজ করতে পছন্দ করব finite amount of space and a reasonable amount of time?:)
কোডডডিক্ট

10
@ এসএলক্স - প্রথম নোডে লুপটি প্রয়োজনীয় নয়। এটি অর্ধেক ফিরে লুপ করতে পারেন।
jjjuma

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

3
সত্য কথা বলতে গেলে, বেশিরভাগ "অ্যালগোরিদম জেনে রাখা" এর মতো - আপনি গবেষণা স্তরের জিনিসগুলি না করলে!
ল্যারি

12
@ গ্যারিএফ এবং এখনও উত্তরটি না জানলে তারা কী করবে তা জানার বিষয়টি প্রকাশিত হবে। উদাহরণস্বরূপ, তারা কী পদক্ষেপ গ্রহণ করবে, কার সাথে তারা কাজ করবে, তারা অ্যালগোরিদমেক জ্ঞানের অভাব কাটিয়ে উঠতে কী করবে?
ক্রিস নাইট 21

উত্তর:


538

আপনি ফ্লয়েডের চক্র-সন্ধানকারী অ্যালগরিদম ব্যবহার করতে পারেন , এটি কচ্ছপ এবং হরে আলগোরিদিম হিসাবেও পরিচিত ।

ধারণা লিস্টে দুই রেফারেন্স আছে এবং তাদের দিকে সরানো হয় বিভিন্ন গতি । ফরওয়ার্ড এক সরান 1নোড এবং অন্যান্য 2নোড।

  • যদি লিঙ্কযুক্ত তালিকার একটি লুপ থাকে তবে তারা অবশ্যই মিলবে।
  • অন্য দুটি রেফারেন্সের (বা তাদের next) হয়ে যাবে null

জাভা ফাংশন আলগোরিদিম বাস্তবায়ন:

boolean hasLoop(Node first) {

    if(first == null) // list does not exist..so no loop either
        return false;

    Node slow, fast; // create two references.

    slow = fast = first; // make both refer to the start of the list

    while(true) {

        slow = slow.next;          // 1 hop

        if(fast.next != null)
            fast = fast.next.next; // 2 hops
        else
            return false;          // next node null => no loop

        if(slow == null || fast == null) // if either hits null..no loop
            return false;

        if(slow == fast) // if the two ever meet...we must have a loop
            return true;
    }
}

29
আবার fast.nextকল করার আগে নাল-চেক nextকরতে হবে:if(fast.next!=null)fast=fast.next.next;
কেম্পট্রেকেকেন

12
আপনার ধীরে ধীরে দ্রুত জাম্পিং রোধ করতে কেবল (ধীর == দ্রুত) তবে: (ধীর == দ্রুত || ধীর.নেক্সট == দ্রুত) আপনার পরীক্ষা করা উচিত
ওলেগ রাজ্জুলিয়ায়েভ

13
আমি ভুল ছিলাম: দ্রুত ধীরে ধীরে লাফিয়ে উঠতে পারে না, কারণ পরবর্তী ধাপে ধীরে ধীরে ঝাঁপিয়ে পড়ার মতো ধীরে ধীরে একই
পোজ

4
ধীর == নাল জন্য চেক অপ্রয়োজনীয় যদি না তালিকার কেবল একটি নোড থাকে। আপনি নোড.নেক্সটে একটি কল থেকে মুক্তি পেতে পারেন। লুপটির
কায় সররাতে

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

127

এখানে দ্রুত / ধীর সমাধানের একটি পরিমার্জন দেওয়া হয়েছে, যা সঠিকভাবে বিজোড় দৈর্ঘ্যের তালিকা পরিচালনা করে এবং স্বচ্ছতার উন্নতি করে improves

boolean hasLoop(Node first) {
    Node slow = first;
    Node fast = first;

    while(fast != null && fast.next != null) {
        slow = slow.next;          // 1 hop
        fast = fast.next.next;     // 2 hops 

        if(slow == fast)  // fast caught up to slow, so there is a loop
            return true;
    }
    return false;  // fast reached null, so the list terminates
}

2
সুন্দর এবং সংযুক্তি। এই কোডটি ধীর == দ্রুত কিনা তা পরীক্ষা করে অনুকূলিত করা যায় || (quick.next! = নাল && ধীর = quick.next); :)
arachnode.net

11
@ arachnode.net এটি কোনও অপ্টিমাইজেশন নয়। তাহলে slow == fast.nextতারপর slowসমান হবে fastখুব পরবর্তী পুনরাবৃত্তিতে করুন; এটি প্রতিটি পুনরাবৃত্তির জন্য অতিরিক্ত পরীক্ষার ব্যয়ে কেবলমাত্র একটি পুনরাবৃত্তি সংরক্ষণ করে।
জেসন সি 23

@ ana01 এর slowআগে fastএকই সূত্রটি অনুসরণ করতে পারে না কারণ এটি একই ধরণের রেফারেন্স অনুসরণ করে (যদি আপনার তালিকায় একযোগে পরিবর্তন না হয় যার ক্ষেত্রে সমস্ত বেট বন্ধ থাকে)।
ডেভ এল।

কৌতূহলের বাইরে কীভাবে বিজোড় সংখ্যার জন্য এটি কাজ করে? বিজোড় দৈর্ঘ্যের লিঙ্কযুক্ত তালিকাগুলি এখনও কচ্ছপটি পাস করতে পারে না?
TheGreenCabbage

1
@ থ্রগ্রিনক্যাবেজ হারের প্রতিটি পুনরুক্তি কচ্ছপের চেয়ে 1 ধাপ এগিয়ে। সুতরাং খরগোশটি যদি 3 টি পদক্ষেপের পিছনে থাকে, তবে পরবর্তী পুনরাবৃত্তিতে এটি দুটি হপ নেয় এবং কচ্ছপটি একটি হপ নেয়, এবং এখন খরগোশটি 2 ধাপ পিছনে রয়েছে। পরবর্তী পুনরাবৃত্তির পরে হারে 1 হপ পিছনে রয়েছে এবং তারপরে এটি ঠিক ধরা পড়ে। কচ্ছপটি একটি গ্রহণ করার সময় যদি খরগোশটি 3 টি ছোঁয়া নেয়, তবে এটি এড়াতে পারে কারণ এটি প্রতিবার 2 দ্বারা লাভ করবে তবে যেহেতু এটি প্রতিটি পুনরাবৃত্তি কেবল 1 দ্বারা লাভ করে তা অতীত ছাড়তে পারে না।
ডেভ এল।

52

ফ্লয়েডের অ্যালগরিদমের চেয়ে ভাল

রিচার্ড ব্রেন্ট একটি বিকল্প চক্র সনাক্তকরণ অ্যালগরিদম বর্ণনা করেছিলেন , যা হরে এবং কচ্ছপের [ফ্লয়েডের চক্র] এর মতো বেশ, এখানে ধীর গতি নড়ছে না, তবে পরে স্থির হয়ে দ্রুত নোডের অবস্থানে "টেলিপোর্ট করা" হয়েছে অন্তর।

বর্ণনাটি এখানে উপলভ্য: http://www.siafoo.net/algorithm/11 ব্রেন্ট দাবি করেছেন যে তার অ্যালগরিদম ফ্লয়েডের চক্র অ্যালগরিদমের চেয়ে 24 থেকে 36% গতিযুক্ত। ও (এন) সময়ের জটিলতা, ও (1) স্থান জটিলতা।

public static boolean hasLoop(Node root){
    if(root == null) return false;

    Node slow = root, fast = root;
    int taken = 0, limit = 2;

    while (fast.next != null) {
        fast = fast.next;
        taken++;
        if(slow == fast) return true;

        if(taken == limit){
            taken = 0;
            limit <<= 1;    // equivalent to limit *= 2;
            slow = fast;    // teleporting the turtle (to the hare's position) 
        }
    }
    return false;
}

এই উত্তর দুর্দান্ত!
ভালিন077

1
আপনার উত্তরটি সত্যিই পছন্দ হয়েছে, এটি আমার ব্লগে অন্তর্ভুক্ত করেছে - k2code.blogspot.in/2010/04/…
কিনশুক 4

আপনার চেক করা দরকার কেন slow.next != null? আমি যতদূর দেখতে পাচ্ছি slowসর্বদা পিছনে বা সমান fast
TWiStErRob

আমি এটি অনেক আগে করেছি, যখন আমি অ্যালগরিদম শিখতে শুরু করি। কোডটি সম্পাদনা করেছেন। ধন্যবাদ :)
অশোক বিজয় দেবনাথ

50

টার্টল এবং খরগোশের বিকল্প সমাধান, খুব সুন্দর নয়, আমি অস্থায়ীভাবে তালিকাটি পরিবর্তন করেছি:

এই তালিকাটি হাঁটাচলা করা এবং আপনি যাওয়ার সাথে সাথে এটিকে বিপরীত করা। তারপরে, আপনি যখন ইতিমধ্যে পরিদর্শন করা কোনও নোডে পৌঁছাবেন তখন এর পরবর্তী পয়েন্টারটি "পিছনের দিকে" নির্দেশ করবে, পুনরাবৃত্তির firstপুনরায় অগ্রসর হতে হবে , যেখানে এটি শেষ হয়।

Node prev = null;
Node cur = first;
while (cur != null) {
    Node next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
}
boolean hasCycle = prev == first && first != null && first.next != null;

// reconstruct the list
cur = prev;
prev = null;
while (cur != null) {
    Node next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
}

return hasCycle;

পরীক্ষার কোড:

static void assertSameOrder(Node[] nodes) {
    for (int i = 0; i < nodes.length - 1; i++) {
        assert nodes[i].next == nodes[i + 1];
    }
}

public static void main(String[] args) {
    Node[] nodes = new Node[100];
    for (int i = 0; i < nodes.length; i++) {
        nodes[i] = new Node();
    }
    for (int i = 0; i < nodes.length - 1; i++) {
        nodes[i].next = nodes[i + 1];
    }
    Node first = nodes[0];
    Node max = nodes[nodes.length - 1];

    max.next = null;
    assert !hasCycle(first);
    assertSameOrder(nodes);
    max.next = first;
    assert hasCycle(first);
    assertSameOrder(nodes);
    max.next = max;
    assert hasCycle(first);
    assertSameOrder(nodes);
    max.next = nodes[50];
    assert hasCycle(first);
    assertSameOrder(nodes);
}

লুপ যখন প্রথমটি ব্যতীত অন্য কোনও নোডের দিকে নির্দেশ করছে তখন কি বিপরীতটি সঠিকভাবে কাজ করে? প্রাথমিক লিঙ্কযুক্ত তালিকার তালিকাটি যদি 1-> 2-> 3-> 4-> 5-> 2 (5 থেকে 2 পর্যন্ত একটি চক্র সহ) এর মতো হয়, তবে বিপরীত তালিকাটি 1-> 2 <-3 <-4 এর মতো দেখায় <-5? এবং যদি বিপরীতটি হয়, তবে চূড়ান্ত পুনর্গঠন তালিকাটি স্ক্রু করা হবে?
জেনিল

1
@ জেনিল: সে কারণেই আমি সেই শেষ টেস্টকেসটি লিখেছি যেখানে সর্বশেষ নোড তালিকার মাঝখানে points পুনর্গঠন যদি কাজ না করে, তবে এই পরীক্ষাটি ব্যর্থ হবে। আপনার উদাহরণ সম্পর্কে: 1-> 2-> 3-> 5-> 2 এর বিপরীতটি 1-> 2-> 5-> 4-> 3-> 2 হবে, কারণ তালিকার শেষে কেবল লুপটি বন্ধ হয়ে যায় পৌঁছে গেছে, যখন লুপের শেষ (যা আমরা সহজেই আবিষ্কার করতে পারি না) পৌঁছে যায়।
মেরিটন

28

কচ্ছপ এবং খরগোশ

কটাক্ষপাত পোলার্ড এর Rho অ্যালগরিদম । এটি একেবারে একই সমস্যা নয় তবে আপনি এটি থেকে যুক্তিটি বুঝতে পারবেন এবং এটি লিঙ্কযুক্ত তালিকার জন্য প্রয়োগ করবেন।

(আপনি যদি অলস হন তবে আপনি কেবল চক্র সনাক্তকরণ পরীক্ষা করতে পারেন - কচ্ছপ এবং খরগোশের অংশটি পরীক্ষা করতে পারেন ))

এটির জন্য কেবল রৈখিক সময় এবং ২ টি অতিরিক্ত পয়েন্টার প্রয়োজন।

জাভাতে:

boolean hasLoop( Node first ) {
    if ( first == null ) return false;

    Node turtle = first;
    Node hare = first;

    while ( hare.next != null && hare.next.next != null ) {
         turtle = turtle.next;
         hare = hare.next.next;

         if ( turtle == hare ) return true;
    }

    return false;
}

(বেশিরভাগ সমাধান উভয় nextএবং next.nextনাল উভয়ই পরীক্ষা করে না Also এছাড়াও, যেহেতু কচ্ছপ সর্বদা পিছনে থাকে তাই আপনাকে এটি নালার জন্য পরীক্ষা করতে হবে না - খরগোশটি ইতিমধ্যে এটি করেছিল))


13

ব্যবহারকারীর ইউনিকর্নড্যাডিক্টের উপরে একটি দুর্দান্ত অ্যালগরিদম রয়েছে তবে দুর্ভাগ্যক্রমে এটি বিজোড় দৈর্ঘ্যের নন-লুপ তালিকার জন্য একটি বাগ রয়েছে> = 3 সমস্যাটি হ'ল fastতালিকার সমাপ্তির ঠিক আগে "আটকে" slowযেতে পারে, এটি ধরা পড়ে এবং একটি লুপ (ভুলভাবে) সনাক্ত হয়েছে।

এখানে সংশোধন করা অ্যালগরিদম।

static boolean hasLoop(Node first) {

    if(first == null) // list does not exist..so no loop either.
        return false;

    Node slow, fast; // create two references.

    slow = fast = first; // make both refer to the start of the list.

    while(true) {
        slow = slow.next;          // 1 hop.
        if(fast.next == null)
            fast = null;
        else
            fast = fast.next.next; // 2 hops.

        if(fast == null) // if fast hits null..no loop.
            return false;

        if(slow == fast) // if the two ever meet...we must have a loop.
            return true;
    }
}

10

এই প্রসঙ্গে, পাঠ্য সামগ্রীগুলিতে সর্বত্র ভার রয়েছে। আমি কেবল একটি ডায়াগ্রাম্যাটিক উপস্থাপনা পোস্ট করতে চেয়েছিলাম যা সত্যিই ধারণাটি উপলব্ধি করতে আমাকে সহায়তা করেছিল।

যখন পয়েন্ট পি তে দ্রুত এবং ধীর মিলিত হয়,

দূরত্বটি দ্রুত = a + b + c + b = a + 2b + c দ্বারা ভ্রমণ করেছে

দূরত্ব ধীরে ধীরে ভ্রমণ করেছে = a + b

যেহেতু দ্রুতগতি ধীরের চেয়ে 2 গুণ দ্রুত হয়। সুতরাং একটি + 2 বি + সি = 2 (এ + বি) , তারপরে আমরা একটি = সি পাই ।

সুতরাং যখন অন্য ধীর পয়েন্টার আবার মাথা থেকে q এ চলে যায়, একই সময়ে দ্রুত পয়েন্টার পি থেকে কিউতে চলতে থাকে , তাই তারা একসাথে পয়েন্ট Q এ মিলিত হয়।

এখানে চিত্র বর্ণনা লিখুন

public ListNode detectCycle(ListNode head) {
    if(head == null || head.next==null)
        return null;

    ListNode slow = head;
    ListNode fast = head;

    while (fast!=null && fast.next!=null){
        fast = fast.next.next;
        slow = slow.next;

        /*
        if the 2 pointers meet, then the 
        dist from the meeting pt to start of loop 
        equals
        dist from head to start of loop
        */
        if (fast == slow){ //loop found
            slow = head;
            while(slow != fast){
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }            
    }
    return null;
}

2
হাজার হাজার শব্দের চেয়ে বেশি দামের একটি ছবি। ঝরঝরে ও সরল ব্যাখ্যার জন্য ধন্যবাদ!
Calios

1
ইন্টারনেটে সেরা ব্যাখ্যা। কেবল যুক্ত করুন যে এটি লিনিয়ার সময়ের পরে দ্রুত এবং ধীর পয়েন্টার একত্রিত করে
বরুণপাণ্ডে

যদি aলুপ দৈর্ঘ্যের চেয়ে বড় হয় তবে দ্রুত একাধিক লুপ তৈরি distance (fast) = a + b + b + cকরবে এবং সূত্রটি a + (b+c) * k + bঅতিরিক্ত পরামিতি প্রবর্তন করতে পরিবর্তিত হবে kযা দ্রুত এক দ্বারা তৈরি লুপের সংখ্যা গণনা করে।
বেন

9

অ্যালগরিদম

public static boolean hasCycle (LinkedList<Node> list)
{
    HashSet<Node> visited = new HashSet<Node>();

    for (Node n : list)
    {
        visited.add(n);

        if (visited.contains(n.next))
        {
            return true;
        }
    }

    return false;
}

জটিলতা

Time ~ O(n)
Space ~ O(n)

স্পেস জটিলতা ও (2 এন) কেমন?
প্রোগ্রামার

@ ব্যবহারকারী 3543449 আপনি ঠিক বলেছেন, এটি ঠিক n, স্থির হওয়া উচিত
খালেদ.কে

1
এটি আসলে সময় ~ O (n ^ 2) হওয়ায় প্রত্যেকটিতে অ্যারেলিস্টের জন্য চেক থাকা ও (এন) নেয় এবং সেগুলির মধ্যে ও (এন) রয়েছে। রৈখিক সময়ের পরিবর্তে একটি হ্যাশসেট ব্যবহার করুন।
ডেভ এল

3
এটি চক্রের জন্য নয় তবে উপাদানগুলি equalsএবং ব্যবহার করে সদৃশ মানগুলির জন্য পরীক্ষা করে না hashCode। এটি একই জিনিস নয়। এবং এটি nullসর্বশেষ উপাদানটির উপর আলোচনা করে। এবং প্রশ্নটি একটিতে নোডগুলি সঞ্চয় করার বিষয়ে কিছুই বলেনি LinkedList
লই

2
@ লি এটি একটি ছদ্ম-কোড, এটি জাভা কোড নয়, এজন্যই আমি এটিকে অ্যালগরিদম
খালেদ.কে।

8

নিম্নলিখিতটি সর্বোত্তম পদ্ধতি নাও হতে পারে - এটি ও (এন ^ 2)। যাইহোক, এটি কাজ শেষ করার জন্য পরিবেশন করা উচিত (শেষ পর্যন্ত)

count_of_elements_so_far = 0;
for (each element in linked list)
{
    search for current element in first <count_of_elements_so_far>
    if found, then you have a loop
    else,count_of_elements_so_far++;
}

() এর জন্য তালিকায় থাকা কয়টি উপাদান রয়েছে তা আপনি কীভাবে জানবেন?
জেথ্রো লারসন

@ জেথ্রো লারসন: লিঙ্কযুক্ত তালিকার শেষ নোডটি একটি পরিচিত ঠিকানাকে নির্দেশ করে (অনেকগুলি প্রয়োগে, এটি NULL)। যখন পরিচিত ঠিকানাটি পৌঁছেছে তখন লুপটি শেষ করুন।
স্পার্কি

3
public boolean hasLoop(Node start){   
   TreeSet<Node> set = new TreeSet<Node>();
   Node lookingAt = start;

   while (lookingAt.peek() != null){
       lookingAt = lookingAt.next;

       if (set.contains(lookingAt){
           return false;
        } else {
        set.put(lookingAt);
        }

        return true;
}   
// Inside our Node class:        
public Node peek(){
   return this.next;
}

আমাকে আমার অজ্ঞতা ক্ষমা করুন (আমি এখনও জাভা এবং প্রোগ্রামিংয়ে মোটামুটি নতুন) তবে উপরের কাজটি কেন করবে না?

আমার ধারণা এটি স্থির স্থানটির সমস্যা সমাধান করে না ... তবে এটি কমপক্ষে কোনও যুক্তিসঙ্গত সময়ে সেখানে পৌঁছে যায়, তাই না? এটি কেবলমাত্র লিঙ্কযুক্ত তালিকার জায়গাগুলি এবং n উপাদানগুলির সাথে একটি সেটের স্থান গ্রহণ করবে (যেখানে এন লিঙ্কযুক্ত তালিকার উপাদানগুলির সংখ্যা, বা এটি লুপে না পৌঁছা পর্যন্ত উপাদানগুলির সংখ্যা)। এবং সময়ের জন্য, সবচেয়ে খারাপ ক্ষেত্রে বিশ্লেষণ, আমার ধারণা, ও (এনলগ (এন)) এর পরামর্শ দেবে। () জাভাদোকটি অন্তর্ভুক্ত রয়েছে ()গুলির জন্য সোর্টসেট লুক আপগুলি হ'ল ল্যাভ (এন) (তবে জাভাদোকটি পরীক্ষা করুন তবে আমি নিশ্চিত যে ট্রিসেটের অন্তর্নিহিত কাঠামোটি ট্রি ম্যাপ, যার পরিবর্তে একটি লাল-কালো গাছ) এবং সবচেয়ে খারাপ ক্ষেত্রে (কোনও লুপ নেই, বা খুব শেষে লুপ), এটি এন লুক আপ করতে হবে।


2
হ্যাঁ কিছু ধরণের সেট সহ একটি সমাধান সূক্ষ্মভাবে কাজ করে, তবে তালিকার আকারের সাথে সমানুপাতিক স্থান প্রয়োজন।
jjjuma

3

যদি আমাদের ক্লাসটি এম্বেড করার অনুমতি দেওয়া হয় Nodeতবে আমি নীচে এটি প্রয়োগ করে নিয়েই সমস্যাটি সমাধান করব solve hasLoop()ও (এন) সময়ে চালিত হয় এবং কেবলমাত্র স্থান নেয় counter। এটি কি উপযুক্ত সমাধান বলে মনে হচ্ছে? বা এম্বেড না করে এটি করার কোনও উপায় আছে Node? (স্পষ্টতই, বাস্তব বাস্তবায়নে আরও কিছু পদ্ধতি থাকবে, যেমন RemoveNode(Node n)ইত্যাদি)

public class LinkedNodeList {
    Node first;
    Int count;

    LinkedNodeList(){
        first = null;
        count = 0;
    }

    LinkedNodeList(Node n){
        if (n.next != null){
            throw new error("must start with single node!");
        } else {
            first = n;
            count = 1;
        }
    }

    public void addNode(Node n){
        Node lookingAt = first;

        while(lookingAt.next != null){
            lookingAt = lookingAt.next;
        }

        lookingAt.next = n;
        count++;
    }

    public boolean hasLoop(){

        int counter = 0;
        Node lookingAt = first;

        while(lookingAt.next != null){
            counter++;
            if (count < counter){
                return false;
            } else {
               lookingAt = lookingAt.next;
            }
        }

        return true;

    }



    private class Node{
        Node next;
        ....
    }

}

1

আপনি এটি অবিচ্ছিন্ন ও (1) সময়েও করতে পারেন (যদিও এটি খুব দ্রুত বা দক্ষ না হয়): আপনার কম্পিউটারের স্মৃতিতে সীমিত পরিমাণে নোড থাকতে পারে, এন রেকর্ডস বলুন। আপনি যদি এন রেকর্ডের চেয়ে বেশি অতিক্রম করে থাকেন তবে আপনার একটি লুপ রয়েছে।


এটি ও (1) নয়, বিগ-ও স্বরলিপিতে এই অ্যালগরিদমের কোনও অর্থবহ সময় জটিলতা নেই। বড়-ও-স্বরলিপি আপনাকে কেবল সীমাতে পারফরম্যান্স সম্পর্কে জানায় যেহেতু ইনপুট আকার অনন্তের দিকে যায়। সুতরাং আপনার অ্যালগরিদম ধৃষ্টতা যে উপর তৈরী করে যদি হয় কিছু বৃহৎ এন জন্য N টির বেশি উপাদান বিশিষ্ট কোন তালিকা, তালিকা আকার রানটাইম সীমা পন্থা অনন্ত undefined করা হয়। সুতরাং, জটিলতা "ও (কিছু)" নয়।
fgp

1
 // To detect whether a circular loop exists in a linked list
public boolean findCircularLoop() {
    Node slower, faster;
    slower = head;
    faster = head.next; // start faster one node ahead
    while (true) {

        // if the faster pointer encounters a NULL element
        if (faster == null || faster.next == null)
            return false;
        // if faster pointer ever equals slower or faster's next
        // pointer is ever equal to slower then it's a circular list
        else if (slower == faster || slower == faster.next)
            return true;
        else {
            // advance the pointers
            slower = slower.next;
            faster = faster.next.next;
        }
    }
}

1
boolean hasCycle(Node head) {

    boolean dec = false;
    Node first = head;
    Node sec = head;
    while(first != null && sec != null)
    {
        first = first.next;
        sec = sec.next.next;
        if(first == sec )
        {
            dec = true;
            break;
        }

    }
        return dec;
}

জাভাতে লিঙ্কযুক্ত তালিকার একটি লুপ সনাক্ত করতে উপরের ফাংশনটি ব্যবহার করুন।


2
প্রায় উপরে আমার উত্তর মত একই, কিন্তু একটি সমস্যা আছে। বিজোড় দৈর্ঘ্যের তালিকাগুলি (লুপগুলি ছাড়াই) তালিকার জন্য এটি একটি নালপয়েন্টার এক্সসেপশন নিক্ষেপ করবে। উদাহরণস্বরূপ, যদি হেড.নেক্সটটি নাল হয়, তবে সেক.এনেক্সট.নেক্সট একটি এনপিই ফেলবে।
ডেভ এল।

1

একটি লিঙ্কযুক্ত তালিকায় একটি লুপ সনাক্তকরণ সহজ উপায়গুলির মধ্যে একটিতে করা যেতে পারে, যার ফলস্বরূপ একটি বাছাই ভিত্তিক পদ্ধতির সাহায্যে হ্যাশম্যাপ বা ও (এনলগএন) ব্যবহার করে ও (এন) জটিলতা তৈরি হয়।

আপনি মাথা থেকে শুরু করে তালিকাটি অতিক্রম করার সময়, ঠিকানার তালিকা অনুসারে বাছাই করা তালিকা তৈরি করুন। আপনি যখন কোনও নতুন ঠিকানা সন্নিবেশ করবেন তখন ঠিকানাটি বাছাই করা তালিকায় ইতিমধ্যে রয়েছে কিনা তা পরীক্ষা করে নিন, যা ও (লগএন) জটিলতা নেয়।


এই apporach এর জটিলতা হ'ল O (N লগ এন)
fgp

0

আমি এটি নির্ধারিত সময় এবং স্থানের একটি নির্দিষ্ট পরিমাণ নেওয়ার কোনও উপায় দেখতে পাচ্ছি না, উভয়ই তালিকার আকারের সাথে বাড়বে।

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

আইটিটিটিহ্যাশম্যাপ .aquals এর পরিবর্তে == ব্যবহার করে যাতে আপনি একই বিষয়বস্তু না রেখে বরং বস্তুটির মেমরিটিতে কোথায় তা পরীক্ষা করে দেখছেন।


3
নির্দিষ্ট সময়ের জন্য এটির পক্ষে অবশ্যই অসম্ভব, কারণ তালিকার একেবারে শেষে লুপ থাকতে পারে, সুতরাং পুরো তালিকাটি অবশ্যই দেখতে হবে। তবে দ্রুত / ধীর অ্যালগরিদম একটি নির্দিষ্ট পরিমাণ মেমরি ব্যবহার করে একটি সমাধান দেখায়।
ডেভ এল।

এটি কি এর অসম্পূর্ণ আচরণের উল্লেখ করছে না, অর্থাত্ এটি লিনিয়ার হে (এন) যেখানে n তালিকার দৈর্ঘ্য। স্থির হবে ও (1)
মার্ক রবসন

0

আমি এই থ্রেডটি পরিচালনা করতে ভীষণ দেরী এবং নতুন হতে পারি। কিন্তু এখনো..

নোডের ঠিকানা এবং "পরবর্তী" নোড পয়েন্ট কেন একটি টেবিলের মধ্যে সংরক্ষণ করা যায়

আমরা যদি এইভাবে ট্যাবলেট করতে পারি

node present: (present node addr) (next node address)

node 1: addr1: 0x100 addr2: 0x200 ( no present node address till this point had 0x200)
node 2: addr2: 0x200 addr3: 0x300 ( no present node address till this point had 0x300)
node 3: addr3: 0x300 addr4: 0x400 ( no present node address till this point had 0x400)
node 4: addr4: 0x400 addr5: 0x500 ( no present node address till this point had 0x500)
node 5: addr5: 0x500 addr6: 0x600 ( no present node address till this point had 0x600)
node 6: addr6: 0x600 addr4: 0x400 ( ONE present node address till this point had 0x400)

সুতরাং একটি চক্র গঠিত হয়।


আপনার সমাধান "স্থির পরিমাণের ধ্রুব পরিমাণ" প্রয়োজনীয়তাটি পাস করে না।
আরনাউড

0

এখানে আমার চলমান কোড।

আমি যা করেছি তা হ'ল O(1)লিঙ্কগুলি ট্র্যাক করে রাখার জন্য তিনটি অস্থায়ী নোড (স্পেস জটিলতা ) ব্যবহার করে লিঙ্কযুক্ত তালিকাটি শ্রদ্ধা করা ।

এটি করার বিষয়ে আকর্ষণীয় সত্যটি লিঙ্কযুক্ত তালিকার চক্রটি সনাক্তকরণে সহায়তা করা কারণ আপনি এগিয়ে যাওয়ার সাথে সাথে আপনি প্রারম্ভিক বিন্দুতে (রুট নোড) ফিরে যাওয়ার আশা করবেন না এবং অস্থায়ী নোডের কোনওটি বাতিল হওয়া উচিত যদি না আপনি একটি চক্র রয়েছে যার অর্থ এটি মূল নোডকে নির্দেশ করে।

এই অ্যালগরিদমের সময় জটিলতা O(n)এবং স্থান জটিলতা O(1)

লিঙ্কযুক্ত তালিকার জন্য এখানে ক্লাস নোড:

public class LinkedNode{
    public LinkedNode next;
}

এখানে তিনটি নোডের সাধারণ পরীক্ষার কেস সহ প্রধান কোড যা শেষ নোডটি দ্বিতীয় নোডের দিকে নির্দেশ করছে:

    public static boolean checkLoopInLinkedList(LinkedNode root){

        if (root == null || root.next == null) return false;

        LinkedNode current1 = root, current2 = root.next, current3 = root.next.next;
        root.next = null;
        current2.next = current1;

        while(current3 != null){
            if(current3 == root) return true;

            current1 = current2;
            current2 = current3;
            current3 = current3.next;

            current2.next = current1;
        }
        return false;
    }

এখানে তিনটি নোডের একটি সহজ পরীক্ষার কেস যা শেষ নোডটি দ্বিতীয় নোডের দিকে নির্দেশ করছে:

public class questions{
    public static void main(String [] args){

        LinkedNode n1 = new LinkedNode();
        LinkedNode n2 = new LinkedNode();
        LinkedNode n3 = new LinkedNode();
        n1.next = n2;
        n2.next = n3;
        n3.next = n2;

        System.out.print(checkLoopInLinkedList(n1));
    }
}

0

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

1-> 2-> 9-> 3 ^ -------- ^ ^

কোডটি এখানে:

boolean loop(node *head)
{
 node *back=head;
 node *front=head;

 while(front && front->next)
 {
  front=front->next->next;
  if(back==front)
  return true;
  else
  back=back->next;
 }
return false
}

আপনি কি নিশ্চিত যে এটি সমস্ত পরিস্থিতিতে সঠিক ফলাফল দেয়? আপনি যদি 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 3 -> ... তালিকায় এই অ্যালগরিদমটি চালান তবে আমি বিশ্বাস করি যে এটি 4 হিসাবে মাথা হিসাবে ফিরে আসবে, যেখানে আপনি চেয়েছিলেন 3.
সুনরিফ

প্রশ্নটি সন্ধান করছে যে সেখানে কোনও লুপ রয়েছে কি না this এই ক্ষেত্রে, হ্যাঁ, প্রশ্নটি পুরোপুরি ঠিকঠাক কাজ করবে এবং মামলার জন্য পছন্দসই বুলিয়ান ফলাফলটি অর্জন করবে you আপনি যদি লুপটি শুরু করেছিলেন সেখান থেকে সঠিক নোড চান, তবে আমরা করব কোডটিতে কিছুটা আরও যুক্ত করা দরকার B তবে যতক্ষণ পর্যন্ত ফলাফল তৈরির বিষয়টি বিবেচনা করা যায়, এই দ্রুততর উপসংহার তৈরি করবে।
সার্থক মেহরা

আপনি প্রশ্নটি সঠিকভাবে পড়েন নি: লেখার সর্বোত্তম উপায় boolean hasLoop(Node first)কোনটি যা সত্য প্রত্যাবর্তন করবে যদি প্রদত্ত নোড একটি লুপের সাথে তালিকার প্রথম এবং অন্যথায় মিথ্যা হয়?
সুনরিফ

আপনার তালিকার জন্য এটি শুকনো রান। প্রথম মানটির অর্থ ব্যাক পয়েন্টার এবং দ্বিতীয় অংশের অর্থ ফরোয়ার্ড পয়েন্টার ((1,1) - (1,3) - (2,3) - (2,5) - (3,5) - (3,7) - (4,7) - (4,4)।
সার্থক মেহরা

আসলে, আমি এখন বুঝতে পারি যে প্রশ্নটি বোঝার দুটি উপায় রয়েছে (বা কমপক্ষে আমি দুটি ভিন্ন ব্যাখ্যা দেখতে পাচ্ছি)। আপনার আলগোরিদিম সঠিক যদি আপনি কেবল কোনও লুপ আছে কিনা তা সন্ধান করেন। তবে আমি ভেবেছিলাম যে প্রশ্নটি জিজ্ঞাসা করছে কোথায় লুপটি শুরু হচ্ছে।
সুনরিফ

0

জাভাতে আমার সমাধানটি এখানে

boolean detectLoop(Node head){
    Node fastRunner = head;
    Node slowRunner = head;
    while(fastRunner != null && slowRunner !=null && fastRunner.next != null){
        fastRunner = fastRunner.next.next;
        slowRunner = slowRunner.next;
        if(fastRunner == slowRunner){
            return true;
        }
    }
    return false;
}

0

উপরের উত্তরে যেমন প্রস্তাবিত হয়েছে তেমনই আপনি ফ্লয়েডের কচ্ছপ অ্যালগরিদমও ব্যবহার করতে পারেন।

এই অ্যালগরিদমটি পরীক্ষা করতে পারে যে কোনও একক সংযুক্ত তালিকায় কোনও বন্ধ চক্র রয়েছে কিনা। এটি দুটি পয়েন্টার সহ একটি তালিকা পুনরাবৃত্তি করে অর্জন করা যেতে পারে যা বিভিন্ন গতিতে চলে যাবে। এইভাবে, যদি একটি চক্র হয় তবে দুটি পয়েন্টার ভবিষ্যতের কোনও সময়ে মিলিত হবে।

লিঙ্কযুক্ত তালিকার ডেটা কাঠামোতে আমার ব্লগ পোস্টটি নির্দ্বিধায় নির্দ্বিধায় অনুভব করুন, যেখানে আমি জাভা ভাষায় উপরে বর্ণিত অ্যালগরিদমের প্রয়োগ সহ একটি কোড স্নিপেটও অন্তর্ভুক্ত করেছি।

শুভেচ্ছা সহ,

আন্ড্রেয়াস (@ এক্সনোরকোড)


0

চক্রটি সনাক্তকরণের জন্য এখানে সমাধান।

public boolean hasCycle(ListNode head) {
            ListNode slow =head;
            ListNode fast =head;

            while(fast!=null && fast.next!=null){
                slow = slow.next; // slow pointer only one hop
                fast = fast.next.next; // fast pointer two hops 

                if(slow == fast)    return true; // retrun true if fast meet slow pointer
            }

            return false; // return false if fast pointer stop at end 
        }

0

// লিঙ্কযুক্ত তালিকার লুপ ফাংশন সন্ধান করুন

int findLoop(struct Node* head)
{
    struct Node* slow = head, *fast = head;
    while(slow && fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
            return 1;
    }
 return 0;
}

-1

এই পদ্ধতির স্পেস ওভারহেড রয়েছে তবে একটি সহজ বাস্তবায়ন:

একটি মানচিত্রে নোড সংরক্ষণ করে লুপ চিহ্নিত করা যায়। এবং নোড রাখার আগে; নোড ইতিমধ্যে বিদ্যমান কিনা তা পরীক্ষা করুন। যদি মানচিত্রে নোড ইতিমধ্যে বিদ্যমান থাকে তবে এর অর্থ হ'ল লিঙ্কযুক্ত তালিকার লুপ রয়েছে।

public boolean loopDetector(Node<E> first) {  
       Node<E> t = first;  
       Map<Node<E>, Node<E>> map = new IdentityHashMap<Node<E>, Node<E>>();  
       while (t != null) {  
            if (map.containsKey(t)) {  
                 System.out.println(" duplicate Node is --" + t  
                           + " having value :" + t.data);  

                 return true;  
            } else {  
                 map.put(t, t);  
            }  
            t = t.next;  
       }  
       return false;  
  }  

এটি প্রশ্নে প্রদত্ত স্থির পরিমাণের নিয়মিত পরিমাণের সাথে মেটাচ্ছে না!
উপার্জন করুন

এটির ওভারহেডের স্থান আছে সম্মত; এটি এই সমস্যাটি সমাধানের জন্য অন্য পদ্ধতি। সুস্পষ্ট পদ্ধতি হ'ল কচ্ছপ এবং কঠোর অ্যালগরিদম।
রাই.স্কুমার

@ ডাউনভোটার, আপনি যদি কারণটিও ব্যাখ্যা করতে পারেন তবে এটি সহায়ক হবে।
rai.skumar

-2
public boolean isCircular() {

    if (head == null)
        return false;

    Node temp1 = head;
    Node temp2 = head;

    try {
        while (temp2.next != null) {

            temp2 = temp2.next.next.next;
            temp1 = temp1.next;

            if (temp1 == temp2 || temp1 == temp2.next) 
                return true;    

        }
    } catch (NullPointerException ex) {
        return false;

    }

    return false;

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