C++ میں لنک شدہ فہرست میں ایک لوپ کا پتہ لگائیں۔

C My Lnk Shd F Rst My Ayk Lwp Ka Pt Lgayy



کسی لنک شدہ فہرست کا اختتامی نوڈ جس میں لوپ ہے NULL کے بجائے اسی فہرست میں کسی دوسرے نوڈ کا حوالہ دے گا۔ اگر کسی لنک شدہ فہرست میں کوئی نوڈ ہے جس تک اگلے پوائنٹر کی پیروی کرکے بار بار رسائی حاصل کی جاسکتی ہے، فہرست کو کہا جاتا ہے۔ ایک سائیکل ہے.

عام طور پر، لنکڈ لسٹ کا آخری نوڈ فہرست کے اختتام کو ظاہر کرنے کے لیے NULL حوالہ سے مراد ہے۔ تاہم، لوپ کے ساتھ منسلک فہرست میں، فہرست کے اختتامی نوڈ سے مراد ابتدائی نوڈ، اندرونی نوڈ، یا خود ہے۔ لہذا، ایسے حالات میں، ہمیں اگلے نوڈ کا NULL کا حوالہ ترتیب دے کر لوپ کی شناخت اور اسے ختم کرنا چاہیے۔ منسلک فہرست میں لوپ کا پتہ لگانے والے حصے کی وضاحت اس مضمون میں کی گئی ہے۔












C++ میں، منسلک فہرست میں لوپس تلاش کرنے کے متعدد طریقے ہیں:



ہیش ٹیبل پر مبنی نقطہ نظر : یہ نقطہ نظر ایک ہیش ٹیبل میں ملاحظہ کردہ نوڈس کے پتے محفوظ کرتا ہے۔ منسلک فہرست میں ایک لوپ موجود ہے اگر ہیش ٹیبل میں نوڈ پہلے سے موجود ہے جب اسے دوبارہ دیکھا جاتا ہے۔



فلائیڈ کا سائیکل اپروچ : 'کچھوا اور خرگوش' الگورتھم، جسے عام طور پر Floyd’s cycl-finding algorithm کہا جاتا ہے: یہ تکنیک دو پوائنٹرز کا استعمال کرتی ہے، ایک دوسرے سے زیادہ آہستہ اور دوسرا زیادہ تیزی سے حرکت کرتا ہے۔ تیز پوائنٹر بالآخر سست پوائنٹر کو پیچھے چھوڑ دے گا اگر لنک کردہ فہرست میں کوئی لوپ ہے، جو لوپ کے وجود کو ظاہر کرتا ہے۔





تکراری طریقہ : یہ طریقہ خود کو بار بار کال کرکے منسلک فہرست سے گزرتا ہے۔ منسلک فہرست میں ایک لوپ ہوتا ہے اگر موجودہ نوڈ پہلے ملاحظہ کیا گیا ہو۔

اسٹیک پر مبنی نقطہ نظر : یہ نقطہ نظر ایک اسٹیک میں ملاحظہ کردہ نوڈس کے پتے محفوظ کرتا ہے۔ لنک شدہ فہرست میں ایک لوپ موجود ہے اگر کوئی نوڈ اسٹیک میں پہلے سے موجود ہے جب اسے دوبارہ دیکھا جاتا ہے۔



آئیے تصور کو سمجھنے کے لیے ہر نقطہ نظر کو تفصیل سے بیان کرتے ہیں۔

نقطہ نظر 1: ہیش سیٹ اپروچ

ہیشنگ کا استعمال سب سے سیدھا طریقہ ہے۔ یہاں، ہم نوڈ ایڈریسز کے ساتھ ہیش ٹیبل رکھتے ہوئے ایک ایک کرکے فہرست کو دیکھتے ہیں۔ لہذا، ایک لوپ موجود ہے اگر ہم کبھی بھی موجودہ نوڈ کے اگلے پتے پر چلتے ہیں جو ہیش ٹیبل میں پہلے سے موجود ہے۔ دوسری صورت میں، اگر ہم NULL میں چلتے ہیں تو لنکڈ لسٹ میں کوئی لوپ نہیں ہے (یعنی لنکڈ لسٹ کے آخر تک پہنچ جائے گا)۔

اس حکمت عملی کو عملی جامہ پہنانا کافی آسان ہوگا۔

منسلک فہرست کو عبور کرتے ہوئے، ہم ایک غیر ترتیب شدہ_ہیش میپ کا استعمال کریں گے اور اس میں نوڈس شامل کرتے رہیں گے۔

اب، ایک بار جب ہم ایک نوڈ کے سامنے آتے ہیں جو نقشے میں پہلے سے دکھایا گیا ہے، تو ہم جان لیں گے کہ ہم لوپ کے آغاز پر پہنچ چکے ہیں۔

    • اس کے علاوہ، ہم نے ہر قدم پر دو پوائنٹر رکھے، ہیڈ نوڈ موجودہ نوڈ کی طرف اشارہ کرنا اور آخری نوڈ اعادہ کرتے ہوئے موجودہ نوڈ کے سابقہ ​​نوڈ کی طرف اشارہ کرنا۔
    • جیسا کہ ہمارے ہیڈ نوڈ اب لوپ کے اسٹارٹ نوڈ کی طرف اشارہ کر رہا ہے اور اس طرح آخری نوڈ اس نوڈ کی طرف اشارہ کر رہا تھا جس کی طرف سر اشارہ کر رہا تھا (یعنی، یہ اس کی طرف اشارہ کر رہا ہے۔ آخری نوڈ لوپ کا)، ہمارا ہیڈ نوڈ فی الحال لوپ کے آغاز نوڈ کی طرف اشارہ کر رہا ہے۔
    • ایل سیٹ کرنے سے لوپ ٹوٹ جائے گا۔ astNode->اگلا == NULL .

ایسا کرنے سے، اختتامی لوپ نوڈ لوپ کے ابتدائی نوڈ کا حوالہ دینے کے بجائے، NULL کی طرف اشارہ کرنا شروع کر دیتا ہے۔

ہیشنگ کے طریقہ کار کی اوسط وقت اور جگہ کی پیچیدگی O(n) ہے۔ قارئین کو ہمیشہ آگاہ رہنا چاہیے کہ پروگرامنگ لینگویج میں بلٹ ان ہیشنگ ڈیٹا سٹرکچر کا نفاذ ہیشنگ میں تصادم کی صورت میں کل وقت کی پیچیدگی کا تعین کرے گا۔

مندرجہ بالا طریقہ (HashSet) کے لیے C++ پروگرام کا نفاذ:

#include
نام کی جگہ کا استعمال کرتے ہوئے std؛

ساخت نوڈ {
int قدر
ساخت نوڈ * اگلے؛
} ;

نوڈ * نیا نوڈ ( int قدر )
{
نوڈ * tempNode = نیا نوڈ؛
ٹیمپ نوڈ- > قدر = قدر؛
ٹیمپ نوڈ- > اگلا = NULL؛
واپسی ٹیمپ نوڈ؛
}


// کسی بھی ممکنہ لوپس کی شناخت کریں اور انہیں ختم کریں۔
// میں اس فنکشن کے ساتھ منسلک فہرست۔

باطل فنکشن ہیش میپ ( نوڈ * ہیڈ نوڈ )
{
// ہیش میپ کو لاگو کرنے کے لیے ایک unordered_map بنایا
unordered_map < نوڈ * , int > hash_map؛
// آخری نوڈ کی طرف اشارہ کرتا ہے۔
نوڈ * lastNode = NULL؛
جبکہ ( ہیڈ نوڈ ! = NULL ) {
// اگر نقشے سے کوئی نوڈ غائب ہے تو اسے شامل کریں۔
اگر ( hash_map.find ( ہیڈ نوڈ ) == hash_map.end ( ) ) {
hash_map [ ہیڈ نوڈ ] ++
lastNode = headNode؛
headNode = headNode- > اگلے؛
}
// اگر ایک سائیکل موجود ہے، سیٹ حتمی نوڈ NULL کی طرف اگلا پوائنٹر۔
اور {
lastNode->next = NULL؛
توڑ
}
}
}

// منسلک فہرست دکھائیں
باطل ڈسپلے (نوڈ* ہیڈ نوڈ)
{
جبکہ (headNode != NULL) {
cout << headNode->value << ''؛
headNode = headNode->اگلا؛
}
cout << endl;
}

/* مین فنکشن*/
int main()
{
نوڈ* ہیڈ نوڈ = نیا نوڈ (48)؛
headNode->next = headNode؛
headNode->next = newNode(18)؛
ہیڈ نوڈ->اگلا->اگلا = نیا نوڈ (13)؛
ہیڈ نوڈ->اگلا->اگلا->اگلا = نیا نوڈ (2)؛
ہیڈ نوڈ->اگلا->اگلا->اگلا->اگلا = نیا نوڈ (8)؛

/* لنکڈ لسٹ میں ایک لوپ بنائیں */
ہیڈ نوڈ->اگلا->اگلا->اگلا->اگلا->اگلا = ہیڈ نوڈ->اگلا->اگلا؛
فنکشن ہیش میپ (ہیڈ نوڈ)؛
printf('لنکڈ لسٹ بغیر لوپ کے \n')؛
ڈسپلے (ہیڈ نوڈ)؛

واپسی 0؛
}

آؤٹ پٹ:

بغیر لوپ کے لنک شدہ فہرست
48 18 13 2 8

کوڈ کی مرحلہ وار وضاحت ذیل میں فراہم کی گئی ہے:

    1. بٹس/stdc++.h> ہیڈر فائل، جو تمام عام C++ لائبریریوں پر مشتمل ہے، کوڈ میں شامل ہے۔
    2. 'نوڈ' کے نام سے ایک ڈھانچہ بنایا گیا ہے، اور اس کے دو اراکین ہیں: فہرست میں اگلے نوڈ کا حوالہ اور 'قدر' نامی ایک عدد۔
    3. اس کے ان پٹ کے بطور ایک عددی قدر اور NULL پر سیٹ 'اگلا' پوائنٹر کے ساتھ، فنکشن 'newNode' اس قدر کے ساتھ ایک نیا نوڈ بناتا ہے۔
    4. فنکشن ' فنکشن ہیش میپ' کی وضاحت کی گئی ہے، جو ان پٹ کے طور پر منسلک فہرست کے ہیڈ نوڈ پر ایک پوائنٹر لیتا ہے۔
    5. کے اندر ' فنکشن ہیش میپ ' فنکشن، 'hash_map' کے نام سے ایک غیر ترتیب شدہ_map بنایا جاتا ہے، جو کہ ہیش میپ ڈیٹا سٹرکچر کو نافذ کرنے کے لیے استعمال ہوتا ہے۔
    6. فہرست کے آخری نوڈ کی طرف اشارہ کرنے والے کو NULL سے شروع کیا جاتا ہے۔
    7. A while loop کا استعمال منسلک فہرست کو عبور کرنے کے لیے کیا جاتا ہے، جو ہیڈ نوڈ سے شروع ہوتا ہے اور ہیڈ نوڈ کے NULL ہونے تک جاری رہتا ہے۔
    8. لاسٹ نوڈ پوائنٹر کو موجودہ نوڈ پر جبکہ لوپ کے اندر اپ ڈیٹ کیا جاتا ہے اگر موجودہ نوڈ (ہیڈ نوڈ) ہیش میپ میں پہلے سے موجود نہیں ہے۔
    9. اگر موجودہ نوڈ نقشے میں پایا جاتا ہے، تو اس کا مطلب ہے کہ لنک کردہ فہرست میں ایک لوپ موجود ہے۔ لوپ کو ہٹانے کے لیے، کا اگلا پوائنٹر آخری نوڈ پر مقرر ہے خالی اور جبکہ لوپ ٹوٹ گیا ہے۔
    10. منسلک فہرست کے ہیڈ نوڈ کو 'ڈسپلے' نامی فنکشن کے لیے بطور ان پٹ استعمال کیا جاتا ہے، جو فہرست میں ہر نوڈ کی قدر کو شروع سے ختم کرنے کے لیے آؤٹ پٹ کرتا ہے۔
    11. میں مرکزی فنکشن، ایک لوپ بنانا.
    12. فنکشن 'functionHashMap' کو ہیڈ نوڈ پوائنٹر کے ساتھ بطور ان پٹ کہا جاتا ہے، جو فہرست سے لوپ کو ہٹا دیتا ہے۔
    13. ترمیم شدہ فہرست 'ڈسپلے' فنکشن کا استعمال کرتے ہوئے ظاہر کی جاتی ہے۔

نقطہ نظر 2: فلائیڈ کی سائیکل

Floyd's cycle detection algorithm، جو اکثر کچھوے اور خرگوش الگورتھم کے نام سے جانا جاتا ہے، منسلک فہرست میں سائیکلوں کا پتہ لگانے کے اس طریقہ کی بنیاد فراہم کرتا ہے۔ 'سست' پوائنٹر اور 'تیز' پوائنٹر، جو فہرست کو مختلف رفتار سے عبور کرتے ہیں، اس تکنیک میں استعمال ہونے والے دو پوائنٹر ہیں۔ تیز پوائنٹر دو قدم آگے بڑھتا ہے جبکہ سست پوائنٹر ہر تکرار میں ایک قدم آگے بڑھتا ہے۔ اگر دو پوائنٹس کبھی آمنے سامنے آجائیں تو منسلک فہرست میں ایک سائیکل موجود ہے۔

1. لنکڈ لسٹ کے ہیڈ نوڈ کے ساتھ، ہم دو پوائنٹرز شروع کرتے ہیں جنہیں تیز اور سست کہتے ہیں۔

2. اب ہم لنکڈ لسٹ میں آگے بڑھنے کے لیے ایک لوپ چلاتے ہیں۔ تیز پوائنٹر کو ہر اعادہ کے قدم پر سست پوائنٹر کے سامنے دو مقامات پر منتقل کیا جانا چاہئے۔

3. اگر فاسٹ پوائنٹر فہرست کے آخر تک پہنچ جائے تو لنک شدہ فہرست میں کوئی لوپ نہیں ہوگا (fastPointer == NULL یا fastPointer->اگلا == NULL)۔ اگر نہیں، تو تیز اور سست پوائنٹر آخرکار ملیں گے، جس کا مطلب ہے کہ منسلک فہرست میں ایک لوپ ہے۔

مندرجہ بالا طریقہ کے لیے C++ پروگرام کا نفاذ (Floyd’s Cycle):

#include
نام کی جگہ کا استعمال کرتے ہوئے std؛

/* لنک لسٹ نوڈ */
ساخت نوڈ {
int ڈیٹا؛
ساخت نوڈ * اگلے؛
} ;

/* لوپ کو ہٹانے کا فنکشن۔ */
باطل حذف لوپ ( ساخت نوڈ * ، ساخت نوڈ * ) ;

/* یہ فنکشن لسٹ لوپس کا پتہ لگاتا اور ختم کرتا ہے۔ اس کی پیداوار ہوتی ہے۔ 1
اگر ایک لوپ تھا میں فہرست؛ اور ، یہ واپس آتا ہے۔ 0 . */
int detectAndDeleteLoop ( ساخت نوڈ * فہرست )
{
ساخت نوڈ * slowPTR = فہرست، * fastPTR = فہرست؛

// چیک کرنے کے لیے اعادہ کریں۔ اگر لوپ وہاں ہے.
جبکہ ( سست پی ٹی آر && فاسٹ پی ٹی آر && فاسٹ پی ٹی آر- > اگلے ) {
slowPTR = slowPTR- > اگلے؛
fastPTR = fastPTR- > اگلے- > اگلے؛

/* اگر سست پی ٹی آر اور فاسٹ پی ٹی آر کسی وقت ملتے ہیں۔ پھر وہاں
ایک لوپ ہے */
اگر ( سست پی ٹی آر == تیز پی ٹی آر ) {
ڈیلیٹ لوپ ( سست پی ٹی آر، فہرست ) ;

/* واپسی 1 اس بات کی نشاندہی کرنے کے لیے کہ ایک لوپ دریافت ہوا ہے۔ */
واپسی 1 ;
}
}

/* واپسی 0 اس بات کی نشاندہی کرنے کے لیے کہ کوئی لوپ دریافت نہیں ہوا ہے۔ */
واپسی 0 ;
}

/* منسلک فہرست سے لوپ کو حذف کرنے کا فنکشن۔
loopNode لوپ نوڈس میں سے ایک کی طرف اشارہ کر رہا ہے اور headNode اشارہ کر رہا ہے۔
منسلک فہرست کے آغاز نوڈ پر */
باطل حذف لوپ ( ساخت نوڈ * loopNode، struct Node * ہیڈ نوڈ )
{
ساخت نوڈ * ptr1 = لوپ نوڈ؛
ساخت نوڈ * ptr2 = لوپ نوڈ؛

// شمار کریں کہ کتنے نوڈس ہیں۔ میں لوپ
غیر دستخط شدہ int k = 1 ، میں؛
جبکہ ( ptr1- > اگلے ! = ptr2 ) {
ptr1 = ptr1- > اگلے؛
k++;
}

// ہیڈ نوڈ پر ایک پوائنٹر درست کریں۔
ptr1 = headNode؛

// اور ہیڈ نوڈ کے بعد k نوڈس کا دوسرا پوائنٹر
ptr2 = ہیڈ نوڈ؛
کے لیے ( میں = 0 ; میں < k; i++ )
ptr2 = ptr2- > اگلے؛

/* جب دونوں پوائنٹس کو ایک ساتھ منتقل کیا جاتا ہے،
وہ لوپ پر ٹکرائیں گے ابتدائی نوڈ. */
جبکہ (ptr2 != ptr1) {
ptr1 = ptr1->اگلا؛
ptr2 = ptr2->اگلا؛
}

// نوڈ حاصل کریں'
s آخری پوائنٹر
جبکہ ( ptr2- > اگلے ! = ptr1 )
ptr2 = ptr2- > اگلے؛

/* لوپ کو بند کرنے کے لیے، سیٹ اس کے بعد
لوپ پر نوڈ ختم کرنے والا نوڈ۔ */
ptr2->اگلا = NULL؛
}

/* منسلک فہرست کو ظاہر کرنے کا فنکشن */
باطل ڈسپلے لنکڈ لسٹ (سٹرکچر نوڈ * نوڈ)
{
// لوپ کو حذف کرنے کے بعد منسلک فہرست ڈسپلے کریں۔
جبکہ (نوڈ!= NULL) {
cout << node->data << ''؛
نوڈ = نوڈ-> اگلا؛
}
}

struct Node* newNode (int key)
{
ساخت نوڈ* temp = نیا نوڈ ()؛
temp->ڈیٹا = کلید؛
temp->اگلا = NULL؛
واپسی کا درجہ حرارت؛
}

// مین کوڈ
int main()
{
struct Node* headNode = newNode(48)؛
headNode->next = newNode(18)؛
ہیڈ نوڈ->اگلا->اگلا = نیا نوڈ (13)؛
ہیڈ نوڈ->اگلا->اگلا->اگلا = نیا نوڈ (2)؛
ہیڈ نوڈ->اگلا->اگلا->اگلا->اگلا = نیا نوڈ (8)؛

/* ایک لوپ بنائیں */
ہیڈ نوڈ->اگلا->اگلا->اگلا->اگلا->اگلا = ہیڈ نوڈ->اگلا->اگلا؛
// لنکڈ لسٹ میں لوپ ڈسپلے کریں۔
//displayLinkedList(headNode)؛
detectAndDeleteLoop(headNode)؛

cout << 'کوئی لوپ کے بعد لنک شدہ فہرست \n'؛
ڈسپلے لنکڈ لسٹ (ہیڈ نوڈ)؛
واپسی 0؛
}

آؤٹ پٹ:

بغیر لوپ کے بعد لنک شدہ فہرست
48 18 13 2 8

وضاحت:

    1. متعلقہ ہیڈرز، جیسے 'bits/stdc++.h' اور 'std::cout' پہلے شامل کیے گئے ہیں۔
    2. 'نوڈ' ڈھانچہ، جو منسلک فہرست میں ایک نوڈ کے لئے کھڑا ہے، پھر اعلان کیا جاتا ہے. اگلا پوائنٹر جو فہرست میں درج ذیل نوڈ کی طرف لے جاتا ہے ہر نوڈ میں ایک عدد ڈیٹا فیلڈ کے ساتھ شامل ہوتا ہے۔
    3. پھر، یہ 'deleteLoop' اور 'detectAndDeleteLoop'، دو افعال کی وضاحت کرتا ہے۔ پہلے طریقہ کا استعمال کرتے ہوئے ایک لنک شدہ فہرست سے ایک لوپ کو ہٹا دیا جاتا ہے، اور دوسرے فنکشن کا استعمال کرتے ہوئے فہرست میں ایک لوپ کا پتہ چلتا ہے، جو پھر لوپ کو ہٹانے کے لیے پہلے طریقہ کار کو کال کرتا ہے۔
    4. مین فنکشن میں پانچ نوڈس کے ساتھ ایک نئی لنکڈ لسٹ بنائی جاتی ہے، اور آخری نوڈ کے اگلے پوائنٹر کو تیسرے نوڈ پر سیٹ کرکے ایک لوپ قائم کیا جاتا ہے۔
    5. اس کے بعد یہ 'detectAndDeleteLoop' طریقہ پر کال کرتا ہے جب کہ لنکڈ لسٹ کے ہیڈ نوڈ کو دلیل کے طور پر پاس کرتا ہے۔ لوپس کی شناخت کے لیے، یہ فنکشن 'سلو اینڈ فاسٹ پوائنٹرز' اپروچ استعمال کرتا ہے۔ اس میں دو پوائنٹرز لگائے گئے ہیں جو فہرست کے اوپری حصے سے شروع ہوتے ہیں، سلو پی ٹی آر اور فاسٹ پی ٹی آر۔ جبکہ تیز پوائنٹر ایک ساتھ دو نوڈس کو حرکت دیتا ہے، سست پوائنٹر ایک وقت میں صرف ایک نوڈ کو حرکت دیتا ہے۔ اگر فہرست میں ایک لوپ ہے تو تیز پوائنٹر بالآخر سست پوائنٹر کو پیچھے چھوڑ دے گا، اور دونوں پوائنٹس ایک ہی نوڈ پر آپس میں ٹکرائیں گے۔
    6. فنکشن 'deleteLoop' فنکشن کو طلب کرتا ہے اگر اسے ایک لوپ ملتا ہے، جو فہرست کے ہیڈ نوڈ کو فراہم کرتا ہے اور ان پٹ کے طور پر سست اور تیز پوائنٹرز کے انٹرسیکشن کو فراہم کرتا ہے۔ یہ طریقہ کار فہرست کے ہیڈ نوڈ پر دو پوائنٹرز، ptr1 اور ptr2 قائم کرتا ہے اور لوپ میں نوڈس کی تعداد کو شمار کرتا ہے۔ اس کے بعد، یہ ایک پوائنٹر k نوڈس کو آگے بڑھاتا ہے، جہاں k لوپ میں نوڈس کی کل تعداد ہے۔ پھر، جب تک وہ لوپ کے آغاز پر نہیں ملتے، یہ ایک وقت میں دونوں پوائنٹس ایک نوڈ کو آگے بڑھاتا ہے۔ اس کے بعد نوڈ کے اگلے پوائنٹر کو لوپ کے آخر میں NULL پر سیٹ کرکے لوپ کو توڑ دیا جاتا ہے۔
    7. لوپ کو ہٹانے کے بعد، یہ لنکڈ لسٹ کو حتمی مرحلے کے طور پر دکھاتا ہے۔

طریقہ 3: تکرار

تکرار مسائل کو چھوٹے، آسان ذیلی مسائل میں تقسیم کرکے حل کرنے کی ایک تکنیک ہے۔ Recursion کا استعمال ایک واحد لنک شدہ فہرست کو عبور کرنے کے لیے کیا جا سکتا ہے اس صورت میں کہ فہرست میں اگلے نوڈ کے لیے ایک فنکشن کو مسلسل چلا کر لوپ مل جائے جب تک کہ فہرست کے اختتام تک نہ پہنچ جائے۔

اکیلے منسلک فہرست میں، ایک لوپ کو تلاش کرنے کے لیے تکرار کا استعمال کرنے کے پیچھے بنیادی اصول یہ ہے کہ فہرست کے سر سے شروع کریں، موجودہ نوڈ کو ہر قدم پر وزٹ کیے گئے نشان کے طور پر نشان زد کریں، اور پھر اس فنکشن کو بار بار استعمال کرکے اگلے نوڈ پر جائیں وہ نوڈ. طریقہ مکمل لنک شدہ فہرست پر اعادہ کرے گا کیونکہ اسے بار بار کہا جاتا ہے۔

فہرست میں ایک لوپ ہوتا ہے اگر کوئی نوڈ جس کو پہلے وزٹ کیے گئے کے طور پر نشان زد کیا گیا ہو فنکشن کے ذریعے سامنا کرنا پڑتا ہے۔ اس صورت میں، فنکشن سچ واپس آ سکتا ہے. طریقہ غلط واپس آسکتا ہے اگر یہ وزٹ کیے گئے نوڈ پر چلائے بغیر فہرست کے آخر تک پہنچ جاتا ہے، جو اس بات کی نشاندہی کرتا ہے کہ کوئی لوپ نہیں ہے۔

اگرچہ ایک لنک شدہ فہرست میں ایک لوپ تلاش کرنے کے لیے تکرار کو استعمال کرنے کی یہ تکنیک استعمال کرنے اور سمجھنے کے لیے سیدھی ہے، لیکن وقت اور جگہ کی پیچیدگی کے لحاظ سے یہ سب سے زیادہ مؤثر نہیں ہو سکتی۔

مندرجہ بالا طریقہ کے لیے C++ پروگرام کا نفاذ (دوبارہ):

# شامل کریں
نام کی جگہ کا استعمال کرتے ہوئے std؛

ساخت نوڈ {
int ڈیٹا؛
نوڈ * اگلے؛
bool کا دورہ کیا
} ;

// لنک شدہ فہرست لوپ کا پتہ لگانا فنکشن
bool detectLoopLinkedList ( نوڈ * ہیڈ نوڈ ) {
اگر ( headNode == NULL ) {
واپسی جھوٹا ; // اگر منسلک فہرست خالی ہے، بنیادی معاملہ
}
// ایک لوپ ہے اگر موجودہ نوڈ ہے
// پہلے ہی دورہ کیا گیا ہے.
اگر ( ہیڈ نوڈ- > دورہ کیا ) {
واپسی سچ ہے ;
}
// موجودہ نوڈ میں وزٹیشن مارک شامل کریں۔
ہیڈ نوڈ- > ملاحظہ کیا = سچ ہے ;
// کوڈ کال کرنا کے لیے بعد میں نوڈ بار بار
واپسی لوپ لنکڈ لسٹ کا پتہ لگائیں۔ ( ہیڈ نوڈ- > اگلے ) ;
}

اہم int ( ) {
نوڈ * ہیڈ نوڈ = نیا نوڈ ( ) ;
نوڈ * سیکنڈ نوڈ = نیا نوڈ ( ) ;
نوڈ * تھرڈ نوڈ = نیا نوڈ ( ) ;

ہیڈ نوڈ- > ڈیٹا = 1 ;
ہیڈ نوڈ- > اگلا = سیکنڈ نوڈ؛
ہیڈ نوڈ- > ملاحظہ کیا = جھوٹا ;
سیکنڈ نوڈ- > ڈیٹا = 2 ;
سیکنڈ نوڈ- > اگلا = تیسری نوڈ؛
سیکنڈ نوڈ- > ملاحظہ کیا = جھوٹا ;
تیسری نوڈ- > ڈیٹا = 3 ;
تیسری نوڈ- > اگلا = NULL؛ // کوئی لوپ نہیں۔
تیسری نوڈ- > ملاحظہ کیا = جھوٹا ;

اگر ( لوپ لنکڈ لسٹ کا پتہ لگائیں۔ ( ہیڈ نوڈ ) ) {
cout << 'منسلک فہرست میں لوپ کا پتہ چلا' << endl
} اور {
cout << 'منسلک فہرست میں کوئی لوپ نہیں ملا' << endl
}

// ایک لوپ بنانا
تیسری نوڈ- > اگلا = سیکنڈ نوڈ؛
اگر ( لوپ لنکڈ لسٹ کا پتہ لگائیں۔ ( ہیڈ نوڈ ) ) {
cout << 'منسلک فہرست میں لوپ کا پتہ چلا' << endl
} اور {
cout << 'منسلک فہرست میں کوئی لوپ نہیں ملا' << endl
}

واپسی 0 ;
}

آؤٹ پٹ:

کوئی لوپ نہیں ملا میں منسلک فہرست
لوپ کا پتہ چلا میں منسلک فہرست

وضاحت:

    1. فنکشن لوپ لنکڈ لسٹ کا پتہ لگانا () اس پروگرام میں لنکڈ لسٹ کے ہیڈ کو بطور ان پٹ قبول کرتا ہے۔
    2. تکرار کو فنکشن کے ذریعہ منسلک فہرست میں تکرار کرنے کے لئے استعمال کیا جاتا ہے۔ تکرار کی بنیادی صورت کے طور پر، یہ اس بات کا تعین کرنے سے شروع ہوتا ہے کہ آیا موجودہ نوڈ NULL ہے۔ اگر ایسا ہے تو، طریقہ غلط لوٹاتا ہے، یہ بتاتا ہے کہ کوئی لوپ موجود نہیں ہے۔
    3. موجودہ نوڈ کی 'ملاحظہ شدہ' پراپرٹی کی قیمت کو پھر یہ دیکھنے کے لیے چیک کیا جاتا ہے کہ آیا اس کا پہلے دورہ کیا گیا ہے۔ اگر اس کا دورہ کیا گیا ہو تو یہ درست ہو جاتا ہے، یہ تجویز کرتا ہے کہ ایک لوپ مل گیا ہے۔
    4. فنکشن موجودہ نوڈ کو وزٹ شدہ کے بطور نشان زد کرتا ہے اگر اس کی 'وزٹ شدہ' پراپرٹی کو سچ میں تبدیل کرکے پہلے ہی وزٹ کیا جاچکا ہے۔
    5. وزٹ کیے گئے متغیر کی قدر کو پھر یہ دیکھنے کے لیے چیک کیا جاتا ہے کہ آیا موجودہ نوڈ پہلے وزٹ کیا گیا ہے۔ اگر یہ پہلے استعمال کیا جا چکا ہے تو، ایک لوپ موجود ہونا چاہیے، اور فنکشن درست ہو جاتا ہے۔
    6. آخر میں، فنکشن پاس کر کے فہرست میں اگلے نوڈ کے ساتھ خود کو کال کرتا ہے۔ headNode->اگلا ایک دلیل کے طور پر. بار بار ، یہ اس وقت تک جاری رہتا ہے جب تک کہ یا تو کوئی لوپ نہ مل جائے یا تمام نوڈس کا دورہ نہ کر لیا جائے۔ مطلب، فنکشن وزٹ شدہ متغیر کو درست پر سیٹ کرتا ہے اگر موجودہ نوڈ کو لنکڈ لسٹ میں درج ذیل نوڈ کے لیے بار بار کال کرنے سے پہلے کبھی نہیں دیکھا گیا ہو۔
    7. کوڈ تین نوڈس بناتا ہے اور ان میں ایک منسلک فہرست تیار کرنے کے لیے شامل ہوتا ہے۔ اہم تقریب . طریقہ کار لوپ لنکڈ لسٹ کا پتہ لگانا () پھر فہرست کے ہیڈ نوڈ پر بلایا جاتا ہے۔ پروگرام تیار کرتا ہے ' منسلک فہرست میں لوپ کاٹا گیا۔ 'اگر لوپ لنکڈ لسٹ کا پتہ لگانا () سچ لوٹتا ہے؛ دوسری صورت میں، یہ نکلتا ہے ' لنک کردہ فہرست میں کوئی لوپ نہیں ملا '
    8. اس کے بعد کوڈ آخری نوڈ کے اگلے پوائنٹر کو دوسرے نوڈ پر سیٹ کرکے منسلک فہرست میں ایک لوپ داخل کرتا ہے۔ پھر، فنکشن کے نتائج پر منحصر ہے، یہ چلتا ہے لوپ لنکڈ لسٹ کا پتہ لگانا () دوبارہ اور یا تو پیدا کرتا ہے ' منسلک فہرست میں لوپ کاٹ دیا گیا۔ 'یا' لنک کردہ فہرست میں کوئی لوپ نہیں ملا '

نقطہ نظر 4: اسٹیک کا استعمال

اسٹیک اور 'ڈیپتھ فرسٹ سرچ' (DFS) طریقہ کا استعمال کرتے ہوئے لنک کردہ فہرست میں لوپس تلاش کیے جا سکتے ہیں۔ بنیادی تصور یہ ہے کہ منسلک فہرست کے ذریعے اعادہ کیا جائے، ہر نوڈ کو اسٹیک پر دھکیلنا اگر اس کا پہلے سے دورہ نہیں کیا گیا ہے۔ ایک لوپ کو پہچانا جاتا ہے اگر کوئی نوڈ جو پہلے سے اسٹیک پر ہے دوبارہ سامنا ہوتا ہے۔

یہاں طریقہ کار کی ایک مختصر وضاحت ہے:

    1. وزٹ کیے گئے نوڈس کو ریکارڈ کرنے کے لیے ایک خالی اسٹیک اور ایک متغیر بنائیں۔
    2. اوپر سے شروع کرتے ہوئے، منسلک فہرست کو اسٹیک پر دھکیلیں۔ ایک نوٹ کریں کہ سر کا دورہ کیا گیا ہے.
    3. فہرست میں اگلے نوڈ کو اسٹیک پر دبائیں۔ اس نوڈ میں وزٹیشن مارک شامل کریں۔
    4. جیسا کہ آپ فہرست کو عبور کرتے ہیں، ہر نئے نوڈ کو اسٹیک پر دھکیلیں تاکہ یہ ظاہر کیا جا سکے کہ اس کا دورہ کیا گیا ہے۔
    5. یہ دیکھنے کے لیے چیک کریں کہ آیا کوئی نوڈ جو پہلے دیکھا جا چکا ہے اگر اس کا سامنا ہو تو اسٹیک کے اوپری حصے میں ہے۔ اگر ایسا ہے تو، ایک لوپ مل گیا ہے، اور لوپ کی شناخت اسٹیک میں موجود نوڈس سے ہوتی ہے۔
    6. نوڈس کو اسٹیک سے باہر رکھیں اور اگر کوئی لوپ نہیں ملا تو فہرست کو عبور کرتے رہیں۔

مذکورہ طریقہ کے لیے C++ پروگرام کا نفاذ (اسٹیک)

# شامل کریں
#include
نام کی جگہ کا استعمال کرتے ہوئے std؛

ساخت نوڈ {
int ڈیٹا؛
نوڈ * اگلے؛
} ;

// لوپ کا پتہ لگانے کا فنکشن میں ایک منسلک فہرست
bool detectLoopLinkedList ( نوڈ * ہیڈ نوڈ ) {
اسٹیک < نوڈ *> اسٹیک
نوڈ * tempNode = headNode؛

جبکہ ( tempNode ! = NULL ) {
// اگر اسٹیک کا سب سے اوپر کا عنصر مماثل ہے۔
// موجودہ نوڈ اور اسٹیک خالی نہیں ہے۔
اگر ( ! stack.empty ( ) && stack.top ( ) == ٹیمپ نوڈ ) {
واپسی سچ ;
}
stack.push ( tempNode ) ;
tempNode = tempNode- > اگلے؛
}
واپسی جھوٹا ;
}

اہم int ( ) {
نوڈ * ہیڈ نوڈ = نیا نوڈ ( ) ;
نوڈ * سیکنڈ نوڈ = نیا نوڈ ( ) ;
نوڈ * تھرڈ نوڈ = نیا نوڈ ( ) ;

ہیڈ نوڈ- > ڈیٹا = 1 ;
ہیڈ نوڈ- > اگلا = سیکنڈ نوڈ؛
سیکنڈ نوڈ- > ڈیٹا = 2 ;
سیکنڈ نوڈ- > اگلا = تیسری نوڈ؛
تیسری نوڈ- > ڈیٹا = 3 ;
تیسری نوڈ- > اگلا = NULL؛ // کوئی لوپ نہیں۔

اگر ( لوپ لنکڈ لسٹ کا پتہ لگائیں۔ ( ہیڈ نوڈ ) ) {
cout << 'منسلک فہرست میں لوپ کا پتہ چلا' << endl
} اور {
cout << 'منسلک فہرست میں کوئی لوپ نہیں ملا' << endl
}

// ایک لوپ بنانا
تیسری نوڈ- > اگلا = سیکنڈ نوڈ؛
اگر ( لوپ لنکڈ لسٹ کا پتہ لگائیں۔ ( ہیڈ نوڈ ) ) {
cout << 'منسلک فہرست میں لوپ کا پتہ چلا' << endl
} اور {
cout << 'منسلک فہرست میں کوئی لوپ نہیں ملا' << endl
}

آؤٹ پٹ:

کوئی لوپ نہیں ملا میں منسلک فہرست
لوپ کا پتہ چلا میں منسلک فہرست

وضاحت:

یہ پروگرام یہ معلوم کرنے کے لیے اسٹیک کا استعمال کرتا ہے کہ آیا اکیلے منسلک فہرست میں لوپ ہے۔

  • 1. ان پٹ/آؤٹ پٹ اسٹریم لائبریری اور اسٹیک لائبریری دونوں پہلی لائن میں موجود ہیں۔

    2. معیاری نام کی جگہ دوسری سطر میں شامل ہے، جس سے ہمیں ان پٹ/آؤٹ پٹ اسٹریم لائبریری کے فنکشنز تک رسائی حاصل کرنے کی اجازت ملتی ہے بغیر ان کا 'std::.'

    3. درج ذیل سطر ساخت نوڈ کی وضاحت کرتی ہے، جو دو ارکان پر مشتمل ہے: ایک عدد عدد جسے 'ڈیٹا' کہا جاتا ہے اور ایک دوسرے نوڈ کی طرف اشارہ کرتا ہے جسے 'اگلا' کہا جاتا ہے۔

    4. لنک شدہ فہرست کا سر طریقہ detectLoopLinkedList() کے لیے ایک ان پٹ ہے، جس کی وضاحت اگلی لائن پر کی گئی ہے۔ فنکشن ایک بولین ویلیو تیار کرتا ہے جو اس بات کی نشاندہی کرتا ہے کہ لوپ پایا گیا تھا یا نہیں۔

    5. نوڈ پوائنٹرز کا ایک اسٹیک جسے 'اسٹیک' کہا جاتا ہے اور 'tempNode' نامی نوڈ کا ایک پوائنٹر جو headNode کی قدر کے ساتھ شروع کیا جاتا ہے، دونوں فنکشن کے اندر بنائے جاتے ہیں۔

    6. پھر، جب تک tempNode null pointer نہیں ہے، ہم ایک while loop داخل کرتے ہیں۔

    (a) اسٹیک کے اوپری عنصر کو موجودہ نوڈ سے مماثل ہونا چاہیے تاکہ ہم یہ تعین کر سکیں کہ یہ خالی نہیں ہے۔ اگر یہ معاملہ ہے تو ہم درست واپس آتے ہیں کیونکہ ایک لوپ مل گیا ہے۔

    (b) اگر مذکورہ بالا شرط غلط ہے تو، موجودہ نوڈ پوائنٹر کو اسٹیک پر دھکیل دیا جاتا ہے، اور tempNode کو منسلک فہرست میں درج ذیل نوڈ پر سیٹ کیا جاتا ہے۔

    7. ہم while لوپ کے بعد غلط لوٹتے ہیں کیونکہ کوئی لوپ نہیں دیکھا گیا تھا۔

    8. ہم تین نوڈ آبجیکٹ بناتے ہیں اور انہیں مین() فنکشن میں شروع کرتے ہیں۔ چونکہ پہلی مثال میں کوئی لوپ نہیں ہے، اس لیے ہم ہر نوڈ کے 'اگلے' پوائنٹرز کو ٹھیک سے سیٹ کرتے ہیں۔

نتیجہ:

آخر میں، منسلک فہرست میں لوپس کا پتہ لگانے کا بہترین طریقہ استعمال کے مخصوص کیس اور مسئلہ کی رکاوٹوں پر منحصر ہے۔ Hash Table اور Floyd's cycle-finding algorithm موثر طریقے ہیں اور وہ عملی طور پر بڑے پیمانے پر استعمال ہوتے ہیں۔ اسٹیک اور تکرار کم موثر طریقے ہیں لیکن وہ زیادہ بدیہی ہیں۔