مجموعے
84. ہمیں تکرار کرنے والوں کے بارے میں بتائیں اور ان کا استعمال کیسے کیا جاتا ہے۔
جاوا ڈویلپر کے کسی بھی انٹرویو میں مجموعے ایک پسندیدہ موضوع ہے۔ جب مجموعہ کے درجہ بندی کے بارے میں سوالات کے جوابات دیتے ہیں، امیدوار اکثر کہتے ہیں کہ یہ مجموعہ انٹرفیس سے شروع ہوتا ہے۔ لیکن ایسا نہیں ہے۔ ایک سطح کے اوپر ایک اور انٹرفیس ہے: Iterable ۔ یہ انٹرفیس iterator() طریقہ پر مشتمل ہے، جو آپ کو موجودہ مجموعہ کے لیے Iterator آبجیکٹ تک رسائی فراہم کرتا ہے۔ اور یہ Iterator اعتراض بالکل کیا ہے؟ Iterator آبجیکٹ ایک مجموعہ میں منتقل کرنے اور اس کے عناصر پر تکرار کرنے کی صلاحیت فراہم کرتا ہے، اور صارف کو مجموعہ کے نفاذ کی مخصوص تفصیلات جاننے کی ضرورت نہیں ہے۔ دوسرے الفاظ میں، یہ مجموعہ کے عناصر کی طرف اشارہ کرنے کی ایک قسم ہے، گویا یہ ان میں سے کسی ایک کے اندر جھانک رہا ہے۔ تکرار کرنے والے کے پاس طریقے ہیں جیسے:-
hasNext() — اگر تکرار میں کوئی اور عنصر ہو تو درست ہو جاتا ہے (یہ طریقہ آپ کو بتاتا ہے کہ آپ کب مجموعہ کے اختتام پر پہنچ چکے ہیں)؛
-
next() — تکرار میں اگلی آئٹم واپس کرتا ہے۔ اگر کوئی نہیں ہے، تو NoSuchElementException پھینک دیا جاتا ہے۔ اس کا مطلب یہ ہے کہ اس طریقہ کو استعمال کرنے سے پہلے، hasNext() طریقہ استعمال کرنا بہتر ہے تاکہ یہ یقینی بنایا جا سکے کہ اگلا عنصر موجود ہے۔
-
ہٹائیں () - اگلے() طریقہ کا استعمال کرتے ہوئے موصول ہونے والے آخری عنصر کو مجموعہ سے ہٹاتا ہے ۔ اگر next() کو کبھی نہیں بلایا گیا ہے، تو ریمو() کو کال کرنے سے ایک غیر قانونی اسٹیٹ ایکسیپشن پھینک دیا جائے گا۔
-
forEachRemaining(<Consumer>) — مجموعے کے ہر عنصر پر منظور شدہ کارروائی کو انجام دیتا ہے (یہ طریقہ جاوا 8 میں ظاہر ہوا)۔
List<String> list = new ArrayList<>();
list.add("Hello ");
list.add("World, ");
list.add("It's ");
list.add("Amigo!");
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
iterator.next();
iterator.remove();
}
System.out.println(list.size());
کنسول درج ذیل کو ظاہر کرے گا:
iterator.forEachRemaining(x -> System.out.print(x));
لیکن ایک بار جب ہم یہ کر لیتے ہیں، تو تکرار کرنے والا مزید استعمال کے لیے نا مناسب ہو جاتا ہے: اس نے پوری فہرست کو عبور کر لیا ہے، اور ایک عام تکرار کرنے والے کے پاس پیچھے کی طرف تکرار کرنے کا کوئی طریقہ نہیں ہے۔ اور اس سے LinkedList ، خاص طور پر، اس کے listIterator() طریقہ کی بحث میں ایک اچھا حصہ بنتا ہے ، جو ایک بہتر قسم کی iterator واپس کرتا ہے: ListIterator ۔ باقاعدہ (معیاری) تکرار کرنے والے کے طریقوں کے علاوہ، اس قسم میں درج ذیل ہیں:
-
add(<Element>) — فہرست میں ایک نیا عنصر شامل کرتا ہے۔
-
hasPrevious() — صحیح لوٹاتا ہے اگر اگلے عنصر سے پہلے کوئی عنصر موجود ہو (اگر کوئی پچھلا عنصر ہے)؛
-
nextIndex() - اگلے عنصر کا انڈیکس لوٹاتا ہے۔
-
previous() — پچھلے عنصر کو لوٹاتا ہے (اگلے عنصر سے پہلے والا)؛
-
previousIndex پچھلے عنصر کا انڈیکس لوٹاتا ہے۔
-
set(<Element>) — next() یا previous() کے ذریعے واپس کیے گئے آخری عنصر کی جگہ لے لیتا ہے ۔
85. جاوا کلیکشن فریم ورک میں کون سا مجموعہ درجہ بندی موجود ہے؟
جاوا میں مجموعہ کے دو درجہ بندی ہیں۔ پہلا درجہ بندی مجموعہ درجہ بندی ہے، جس کی ساخت درج ذیل ہے: اسے درج ذیل ذیلی مجموعوں میں تقسیم کیا گیا ہے:-
سیٹ ایک انٹرفیس ہے جو ایک سیٹ کی وضاحت کرتا ہے، ایک ڈیٹا ڈھانچہ جس میں غیر ترتیب شدہ منفرد (غیر دہرائے جانے والے) عناصر ہوتے ہیں۔ اس انٹرفیس میں کچھ معیاری نفاذات ہیں: TreeSet ، HashSet ، اور LinkedHashSet ۔
-
فہرست ایک انٹرفیس ہے جو ڈیٹا ڈھانچے کو بیان کرتا ہے جو اشیاء کی ترتیب شدہ ترتیب کو محفوظ کرتا ہے۔ فہرست میں موجود اشیاء کو فہرست میں ان کے انڈیکس کے ذریعہ ڈالا اور ہٹایا جا سکتا ہے (جیسے ایک صف، لیکن متحرک سائز کے ساتھ)۔ اس انٹرفیس میں کچھ معیاری نفاذ بھی ہیں: ArrayList , Vector ( فرسودہ اور اصل میں استعمال نہیں کیا گیا )، اور LinkedList ۔
-
قطار ایک انٹرفیس ہے جو ڈیٹا ڈھانچے کو بیان کرتا ہے جو فرسٹ ان فرسٹ آؤٹ (FIFO) قطار میں اشیاء کو اسٹور کرتا ہے۔ اس انٹرفیس میں درج ذیل معیاری نفاذات ہیں: LinkedList (یہ ٹھیک ہے، یہ Queue کو بھی لاگو کرتا ہے ) اور PriotityQueue ۔
86. ArrayList کی اندرونی ساخت کیا ہے؟
ایک ArrayList ایک صف کی طرح ہے، لیکن یہ متحرک طور پر پھیل سکتی ہے۔ اس کا کیا مطلب ہے؟ ہڈ کے نیچے، ArrayList ایک عام صف کا استعمال کرتی ہے، یعنی یہ اپنے عناصر کو اندرونی صف میں محفوظ کرتی ہے جس کا ڈیفالٹ سائز 10 سیلز ہوتا ہے۔ داخلی صف بھر جانے کے بعد، ایک نئی صف بنائی جاتی ہے۔ نئی صف کے سائز کا تعین اس فارمولے سے کیا جاتا ہے:<size of the current array> * 3 / 2 + 1
لہذا، اگر ہماری صف کا سائز 10 ہے، تو نئے کا سائز یہ ہوگا: 10*3/2 + 1 = 16۔ پھر اصل (پرانی) صف کی تمام اقدار بلٹ ان کا استعمال کرتے ہوئے اس میں کاپی کی جاتی ہیں۔ System.arraycopy() طریقہ، اور اصل صف کو حذف کر دیا جاتا ہے۔ مختصراً، اسی طرح ArrayList ڈائنامک ریائزنگ کو لاگو کرتی ہے۔ آئیے سب سے زیادہ مقبول ArrayList طریقوں پر غور کریں: 1. add(<Element>) — ارے کے آخر میں ایک عنصر شامل کرتا ہے (آخری خالی سیل میں)، پہلے یہ چیک کرنے کے بعد کہ آیا سرنی میں کوئی سیل دستیاب ہے یا نہیں۔ اگر نہیں تو، ایک نئی صف بنائی جاتی ہے، اور عناصر کو اس میں کاپی کیا جاتا ہے۔ اس آپریشن کی وقتی پیچیدگی O(1) ہے۔ اسی طرح کا ایک add(<Index>, <Element>) طریقہ ہے ۔ یہ ایک عنصر کو فہرست کے آخر میں نہیں جوڑتا ہے (سرنی) بلکہ اس مخصوص سیل میں جو انڈیکس کے ذریعہ اشارہ کیا گیا ہے جو دلیل کے طور پر آیا ہے۔ اس صورت میں، وقت کی پیچیدگی اس بات پر منحصر ہوگی کہ آپ کہاں شامل کرتے ہیں:
- اگر اضافہ فہرست کے آغاز کے قریب ہے، تو وقت کی پیچیدگی O(N) کے قریب ہوگی، کیونکہ نئے کے دائیں جانب واقع تمام عناصر کو ایک سیل کو دائیں جانب منتقل کرنا ہوگا۔
- اگر عنصر کو درمیان میں ڈالا جاتا ہے، تو یہ O(N/2) ہوگا، کیونکہ ہمیں فہرست کے آدھے آئٹمز کو صرف ایک سیل کو دائیں طرف منتقل کرنے کی ضرورت ہے۔
87. لنکڈ لسٹ کی اندرونی ساخت کیا ہے؟
ایک ArrayList اندرونی صف میں عناصر پر مشتمل ہوتی ہے، لیکن ایک LinkedList انہیں دوگنا منسلک فہرست میں اسٹور کرتی ہے۔ اس کا مطلب ہے کہ ہر عنصر میں پچھلے عنصر اور اگلے عنصر کا لنک ہوتا ہے ۔ پہلا عنصر پچھلے عنصر سے منسلک نہیں ہوتا ہے (بالآخر، یہ پہلا ہے)۔ اسے فہرست کا سربراہ بھی سمجھا جاتا ہے، اور LinkedList آبجیکٹ کا اس کا براہ راست حوالہ ہے۔ اسی طرح، آخری عنصر میں اگلا عنصر نہیں ہے، کیونکہ یہ فہرست کی دم ہے۔ لنکڈ لسٹ آبجیکٹ اس کا براہ راست حوالہ بھی دیتا ہے۔ اس کا مطلب ہے کہ فہرست کے سر یا دم تک رسائی کی وقتی پیچیدگی O(1) ہے۔ ArrayList میں ، اگر فہرست بڑھتی ہے، تو اندرونی صف بڑھ جاتی ہے۔ یہاں سب کچھ آسان ہے: حوالہ شامل کرنا اتنا ہی آسان ہے جتنا کہ چند لنکس کو تبدیل کرنا۔ آئیے LinkedList کے سب سے زیادہ استعمال ہونے والے طریقوں کو دیکھتے ہیں: 1. add(<Element>) — فہرست کے آخر میں ایک عنصر شامل کرتا ہے، یعنی آخری عنصر (5) کے بعد، نئے عنصر کا ایک لنک اگلے کے طور پر شامل کیا جائے گا۔ . نئے عنصر میں پچھلا حوالہ اس عنصر (5) کی طرف اشارہ کرے گا جو اب فہرست میں اس سے پہلے ہے۔ اس آپریشن کی وقتی پیچیدگی O(1) ہے، کیونکہ ہمیں صرف آخری عنصر سے لنک کی ضرورت ہے، اور جیسا کہ آپ کو یاد ہوگا، LinkedList آبجیکٹ کا براہ راست ٹیل کا حوالہ ہے، اور اس تک رسائی میں کم سے کم مستقل وقت کی پیچیدگی ہوتی ہے۔ 2. add(<Index>, <Element>) — انڈیکس کے لحاظ سے ایک عنصر شامل کرتا ہے۔ ایک عنصر کو شامل کرتے وقت، ایک فہرست کے وسط میں، یہ طریقہ سب سے پہلے سر اور دم (دونوں سمتوں پر) کے عناصر پر اعادہ کرتا ہے جب تک کہ مطلوبہ جگہ نہ مل جائے۔ اگر ہم تیسرے اور چوتھے عنصر کے درمیان ایک عنصر (اوپر کی تصویر میں) شامل کرتے ہیں، تو تیسرے عنصر کا اگلا لنک نئے عنصر کی طرف اشارہ کرے گا۔ اور نئے شامل کردہ عنصر کا پچھلا حصہ تیسرے کی طرف اشارہ کرے گا۔ بدلے میں، پرانے چوتھے عنصر کا پچھلا لنک اب نئے عنصر کی طرف اشارہ کرے گا، اور نئے عنصر کا اگلا لنک نئے چوتھے عنصر کی طرف اشارہ کرے گا: اس طریقہ کار کی وقت کی پیچیدگی نئے عنصر کے اشاریہ پر منحصر ہے:- اگر یہ سر یا دم کے قریب ہے تو، آپریشن O(1) تک پہنچ جائے گا، کیونکہ عناصر پر اعادہ کرنا درحقیقت ضروری نہیں ہوگا۔
- اگر یہ وسط کے قریب ہے، تو ہمارے پاس O(N/2) ہوگا، کیونکہ طریقہ ایک ہی وقت میں سر اور دم سے تلاش کرے گا جب تک کہ مطلوبہ عنصر نہ مل جائے۔
88. ہیش میپ کی اندرونی ساخت کیا ہے؟
یہ جاوا ڈویلپر امیدواروں سے پوچھنے کے لیے انٹرویو کے سب سے مشہور سوالات میں سے ایک ہو سکتا ہے۔ HashMap کلیدی قدر کے جوڑوں کے ساتھ کام کرتا ہے ۔ وہ HashMap کے اندر کیسے محفوظ ہیں ؟ ایک ہیش میپ میں نوڈس کی اندرونی صف ہوتی ہے:Node<K,V>[] table
پہلے سے طے شدہ طور پر، صف کا سائز 16 ہوتا ہے، اور جب بھی یہ عناصر سے بھر جاتا ہے تو یہ دگنا ہو جاتا ہے (یعنی جب LOAD_FACTOR تک پہنچ جاتا ہے؛ یہ اس حد کی وضاحت کرتا ہے کہ صف کتنی بھری ہو سکتی ہے — پہلے سے طے شدہ طور پر، یہ 0.75 ہے ) . ہر نوڈس کلید کی ایک ہیش، کلید، ایک قدر، اور اگلے عنصر کے حوالے سے ذخیرہ کرتا ہے: اس صورت میں، "اگلے عنصر کا حوالہ" کا مطلب ہے کہ ہم اکیلے سے منسلک فہرست کے ساتھ کام کر رہے ہیں، جہاں ہر عنصر میں اگلے کا لنک ہوتا ہے۔ دوسرے الفاظ میں، ایک HashMap اپنے ڈیٹا کو اکیلے منسلک فہرستوں کی ایک صف میں محفوظ کرتا ہے۔ لیکن مجھے فوراً یہ کہنے دیجئے کہ جب ٹیبل اری کے سیل میں اکیلے سے منسلک فہرست ہوتی ہے جو ایک سے زیادہ عناصر پر مشتمل ہوتی ہے تو یہ اچھی بات نہیں ہے۔ اس رجحان کو ٹکراؤ کہا جاتا ہے ۔ لیکن سب سے پہلے چیزیں. آئیے دیکھتے ہیں کہ پوٹ میتھڈ کا استعمال کرتے ہوئے ایک نیا جوڑا کیسے محفوظ کیا جاتا ہے۔ سب سے پہلے، طریقہ کلید حاصل کرتا ہے hashCode() ۔ اس کا مطلب یہ ہے کہ HashMap کے درست طریقے سے کام کرنے کے لیے ، آپ جو کلیدیں استعمال کرتے ہیں وہ کلاسز ہونی چاہئیں جو اس طریقہ کو اوور رائیڈ کرتی ہیں۔ اس ہیش کوڈ کو پھر اندرونی ہیش() طریقہ میں استعمال کیا جاتا ہے تاکہ ٹیبل ارے کے اندر کچھ سیل کے انڈیکس کا تعین کیا جا سکے۔ نتیجے میں آنے والا انڈیکس ہمیں ٹیبل سرنی کے مخصوص سیل تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ ہمارے یہاں دو صورتیں ہیں:
- سیل خالی ہے - اس صورت میں، نئی نوڈ ویلیو اس میں محفوظ ہے۔
- سیل خالی نہیں ہے — اس صورت میں، چابیاں کی قدروں کا موازنہ کیا جاتا ہے۔ اگر وہ برابر ہیں، تو نئی نوڈ ویلیو پرانی کو اوور رائٹ کر دیتی ہے۔ اگر برابر نہیں ہے، تو اگلی تک رسائی حاصل کی جاتی ہے، اور اس کی کلید کا موازنہ کیا جاتا ہے... اور اسی طرح، جب تک کہ نئی قدر یا تو کچھ پرانی قدر کو اوور رائٹ نہیں کر دیتی یا ہم اکیلے منسلک فہرست کے آخر تک پہنچ جاتے ہیں اور پھر نئی قدر کو وہاں ذخیرہ کرتے ہیں آخری عنصر.
GO TO FULL VERSION