প্রাথমিক ক্ষমতা সহ একটি অ্যারেলিস্ট শুরু করবেন কেন?


149

এর সাধারণ কনস্ট্রাক্টর ArrayListহ'ল:

ArrayList<?> list = new ArrayList<>();

তবে প্রাথমিক ক্ষমতার জন্য একটি পরামিতি সহ একটি ওভারলোডেড কনস্ট্রাক্টরও রয়েছে:

ArrayList<?> list = new ArrayList<>(20);

ArrayListআমরা যখন খুশি তে এতে যুক্ত করতে পারি তবে প্রাথমিক সামর্থ্য সহ একটি তৈরি করা কেন কার্যকর ?


17
আপনি অ্যারেলিস্টের উত্স কোডটি দেখার চেষ্টা করেছেন?
অমিতজি

@ জোয়াচিম সাউর: উত্সটি মনোযোগ সহকারে পড়লে আমাদের মাঝে কিছুটা সচেতনতা পাওয়া যায়। তিনি যদি উত্সটি পড়ে থাকেন তবে আমি চেষ্টা করছিলাম। আমি আপনার দিক বুঝতে পেরেছি। ধন্যবাদ।
অমিতজি

ArrayList, দরিদ্র পারফর্ম সময়ের জন্যই আপনি এই ধরনের একটি কাঠামো ব্যবহার করতে চাইবেন
PositiveGuy

উত্তর:


196

আপনি যদি আগে থেকেই জানেন যে এর আকারটি কী ArrayListহতে চলেছে তবে প্রাথমিক ক্ষমতাটি নির্দিষ্ট করা আরও দক্ষ। আপনি যদি এটি না করেন তবে তালিকাটি বাড়ার সাথে সাথে অভ্যন্তরীণ অ্যারেটি বারবার পুনঃনির্ধারণ করতে হবে।

চূড়ান্ত তালিকাটি যত বড় হবে, পুনরায় স্থানগুলি এড়িয়ে আপনি আরও বেশি সময় সাশ্রয় করবেন।

এটি বলেছিল, প্রাক-বরাদ্দ ছাড়াই, কোনওটির nপিছনে উপাদানগুলি সন্নিবেশ করা ArrayListমোট O(n)সময় নিতে গ্যারান্টিযুক্ত । অন্য কথায়, একটি উপাদান সংযোজন একটি নিয়মিত ধ্রুবক সময় ক্রিয়াকলাপ। প্রতিটি পুনঃনির্ধারণের মাধ্যমে অ্যারের আকারটি তাত্পর্যপূর্ণভাবে বৃদ্ধি করা হয়, সাধারণত কোনও ফ্যাক্টর দ্বারা 1.5। এই পদ্ধতির সাথে, মোট অপারেশনগুলি প্রদর্শিত হতে পারেO(n)


5
যদিও প্রাক বণ্টন পরিচিত মাপ একটি ভাল ধারণা, করছেন না এটা সাধারণত ভয়ানক নয়: আপনার সম্পর্কে প্রয়োজন হবে লগ (ঢ) এর একটি চূড়ান্ত আকার সঙ্গে একটি তালিকার জন্য পুনরায় বরাদ্দ এন , যা একটি অনেক নয়।
জোছিম সৌর

2
@PeterOlson O(n log n)কাজ করা হবে log nকাজ nবার। এটি একটি স্থূল ওভারসিমেট (যদিও এটি ওপরের সীমানা হওয়ার কারণে প্রযুক্তিগতভাবে বড় ও এর সাথে সঠিক)। এটি s + s * 1.5 + s * 1.5 ^ 2 + ... + s * 1.5 ^ m (যেমন s * 1.5 ^ m <n <s * 1.5 ^ (মি + 1)) উপাদানগুলি মোট কপি করে। আমি অঙ্কের পক্ষে খুব ভাল না তাই আমি আপনাকে আমার মাথার উপরের দিক থেকে সঠিক গণিতটি দিতে পারি না (ফ্যাক্টর 2 এর আকার পরিবর্তন করার জন্য, এটি 2 এন, সুতরাং এটি 1.5n দিতে পারে বা একটি ছোট ধ্রুবক নিতে পারে) তবে এটি করা যায় না ' এই যোগফলটি n এর চেয়ে বেশিরভাগ ধ্রুবক ফ্যাক্টর কিনা তা দেখতে খুব বেশি স্কুইটিং লাগবেন না। সুতরাং এটি O (কে * এন) অনুলিপিগুলি নেবে যা অবশ্যই ও (এন)।

1
@ ডেলানন: এ নিয়ে তর্ক করতে পারবেন না! ;) বিটিডাব্লু, আমি আপনার স্কিনিং যুক্তিটি সত্যই পছন্দ করেছি; এটি আমার ট্রিক্সের পুস্তকে যোগ করবে।
এনপিই

6
দ্বিগুণ হয়ে যুক্তিটি করা সহজ। ধরা যাক আপনি পূর্ণ যখন দ্বিগুণ, একটি উপাদান দিয়ে শুরু। মনে করুন আপনি 8 টি উপাদান সন্নিবেশ করতে চান। একটি sertোকান (ব্যয়: 1) দুটি - ডাবল সন্নিবেশ করুন, একটি উপাদান অনুলিপি করুন এবং দুটি সন্নিবেশ করুন (ব্যয়: 2) তিনটি - ডাবল সন্নিবেশ করুন, দুটি উপাদান অনুলিপি করুন, তিনটি সন্নিবেশ করুন (ব্যয়: 3) চারটি প্রবেশ করান (ব্যয়: 1) পাঁচটি - ডাবল সন্নিবেশ করুন, চারটি উপাদান অনুলিপি করুন, পাঁচটি সন্নিবেশ করুন (দাম: 5) ছয়, সাত এবং আট costোকান (দাম: 3) মোট ব্যয়: 1 + 2 + 3 + 1 + 5 + 3 = 16, যা elementsোকানো উপাদানের দ্বিগুণ । এই স্কেচ থেকে আপনি প্রমাণ করতে পারেন যে সাধারণভাবে প্রতি সন্নিবেশ করানো গড় ব্যয় দুটি হয় ।
এরিক লিপার্ট

9
এটাই সময় ব্যয় । আপনি দেখতে পাচ্ছেন যে সময়ের সাথে নষ্ট জায়গার পরিমাণ পরিবর্তিত হয়েছে, কিছু সময়ের 0% এবং কিছু সময় 100% এর কাছাকাছি। 2 থেকে 1.5 বা 4 বা 100 থেকে ফ্যাক্টর পরিবর্তন করা বা যা কিছু নষ্ট স্থানের গড় পরিমাণ এবং অনুলিপি করতে ব্যয় করা গড় সময়ের পরিমাণ পরিবর্তিত করে তবে সময়ের জটিলতা গড়পড়তা ক্ষেত্রেই রৈখিক থেকে যায়, কারণটি ফ্যাক্টর কী তা নয়।
এরিক লিপার্ট

41

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

সুতরাং, যদি আপনি জানেন যে আপনার ওপরের সীমানাটি 20 টি আইটেম, তবে প্রাথমিক প্রস্থের 20 টির সাথে অ্যারে তৈরি করা একটি ডিফল্ট, বলুন 15 এর চেয়ে আরও ভাল এবং এরপরে পুনরায় আকার দিন 15*2 = 30এবং প্রসারণের জন্য চক্রটি নষ্ট করার সময় কেবল 20 ব্যবহার করুন।

পিএস - যেমন অমিতজি বলেছেন, সম্প্রসারণ ফ্যাক্টরটি নির্দিষ্টকরণ বাস্তবায়ন করছে (এই ক্ষেত্রে (oldCapacity * 3)/2 + 1)


9
এটি আসলেint newCapacity = (oldCapacity * 3)/2 + 1;
অমিতজি

25

অ্যারেলিস্টের ডিফল্ট আকার 10 হয়

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
    this(10);
    } 

সুতরাং আপনি যদি 100 বা ততোধিক রেকর্ড যুক্ত করতে চলেছেন তবে আপনি মেমরি পুনর্বিবেচনার ওভারহেড দেখতে পাচ্ছেন।

ArrayList<?> list = new ArrayList<>();    
// same as  new ArrayList<>(10);      

সুতরাং অ্যারেলিস্টে সংরক্ষণ করা হবে এমন উপাদানগুলির সংখ্যা সম্পর্কে যদি আপনার কোনও ধারণা থাকে তবে 10 দিয়ে আরম্ভ করার পরিবর্তে সেই আকারের সাথে অ্যারেলিস্ট তৈরি করা আরও ভাল it


ভবিষ্যতে private static final int DEFAULT_CAPACITY = 10
জেডিকে

17

আমি আসলে 2 মাস আগে এই বিষয়ে একটি ব্লগ পোস্ট লিখেছিলাম । নিবন্ধটি সি # এর জন্য List<T>তবে জাভাটির ArrayListখুব একই রকম বাস্তবায়ন রয়েছে। যেহেতু ArrayListএকটি গতিশীল অ্যারে ব্যবহার করে প্রয়োগ করা হয়, তাই এটি চাহিদা অনুযায়ী আকারে বৃদ্ধি পায়। সুতরাং সক্ষমতা নির্মাতার কারণটি অপ্টিমাইজেশনের উদ্দেশ্যে।

যখন এই আকারগুলির পুনরায় ক্রিয়াকলাপগুলির মধ্যে একটি ঘটে তখন অ্যারেলিস্ট অ্যারের সামগ্রীগুলি একটি নতুন অ্যারেতে অনুলিপি করে যা পুরানোটির ক্ষমতার দ্বিগুণ। এই অপারেশনটি ও (এন) সময়ে চলে।

উদাহরণ

ArrayListআকারটি কীভাবে বাড়বে তার একটি উদাহরণ এখানে দেওয়া হয়েছে :

10
16
25
38
58
... 17 resizes ...
198578
297868
446803
670205
1005308

সুতরাং তালিকার ক্ষমতা দিয়ে শুরু হয় 10, যখন 11 তম আইটেমটি যোগ করা হয় এটি দ্বারা বৃদ্ধি 50% + 1করতে 16। 17 তম আইটেমটিতে ArrayListআবার আবার বাড়ানো হয় 25। এখন উদাহরণটি বিবেচনা করুন যেখানে আমরা একটি তালিকা তৈরি করছি যেখানে পছন্দসই ক্ষমতা ইতিমধ্যে হিসাবে পরিচিত 1000000ArrayListআকার বিন্যাস ছাড়াই তৈরি করা ArrayList.add 1000000সময়গুলিতে কল করবে যা সাধারণত ও (1) বা পুনরায় আকারে ও (এন) লাগে ।

1000000 + 16 + 25 + ... + 670205 + 1005308 = 4015851 অপারেশন

কনস্ট্রাক্টর ব্যবহার করে এটির তুলনা করুন এবং তারপরে কল করুন ArrayList.addযা হে (1) এ চালানোর গ্যারান্টিযুক্ত ।

1000000 + 1000000 = 2000000 অপারেশন

জাভা বনাম সি #

জাভা উপরের মত, 10প্রতিটি পুনরায় আকারে শুরু এবং বাড়ানো 50% + 1। সি # শুরু হয় 4এবং আরও আকারে আক্রমণাত্মকভাবে বৃদ্ধি পায়, প্রতিটি আকারে দ্বিগুণ। 1000000C # এর ব্যবহারের জন্য উপরে থেকে উদাহরণস্বরূপ যোগ করা 3097084অপারেশন।

তথ্যসূত্র


9

একটি অ্যারেলিস্টের প্রাথমিক আকার নির্ধারণ করা, উদাহরণস্বরূপ ArrayList<>(100), অভ্যন্তরীণ মেমরির পুনঃ-বরাদ্দ হওয়া সময়ের সংখ্যা হ্রাস করে।

উদাহরণ:

ArrayList example = new ArrayList<Integer>(3);
example.add(1); // size() == 1
example.add(2); // size() == 2, 
example.add(2); // size() == 3, example has been 'filled'
example.add(3); // size() == 4, example has been 'expanded' so that the fourth element can be added. 

আপনি উপরের উদাহরণে দেখুন - একটি ArrayListপ্রয়োজন হলে প্রসারিত করা যেতে পারে। এটি আপনাকে যা দেখাচ্ছে না তা হ'ল অ্যারেলিস্টের আকারটি সাধারণত দ্বিগুণ হয় (তবে নোট করুন যে নতুন আকারটি আপনার প্রয়োগের উপর নির্ভর করে)। নিম্নলিখিত ওরাকল থেকে উদ্ধৃত করা হয়েছে :

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

স্পষ্টতই, আপনি কোন ধরণের ধারন করবেন তা সম্পর্কে আপনার যদি ধারণা না থাকে তবে আকার নির্ধারণ করা সম্ভবত একটি ভাল ধারণা হবে না - তবে, আপনার যদি মনে একটি নির্দিষ্ট পরিসীমা থাকে তবে প্রাথমিক ক্ষমতা নির্ধারণের ফলে স্মৃতিশক্তির দক্ষতা বৃদ্ধি পাবে ।


3

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


3

এটি প্রতিটি একক অবজেক্টের জন্য পুনর্নির্মাণের সম্ভাব্য প্রচেষ্টা এড়াতে।

int newCapacity = (oldCapacity * 3)/2 + 1;

অভ্যন্তরীণভাবে new Object[]তৈরি করা হয়। আপনি যখন অ্যারেলিস্টে উপাদান যুক্ত করবেন তখন জেভিএমকে
তৈরি করার প্রচেষ্টা new Object[]দরকার। যদি পুনঃনির্ধারণের জন্য আপনার কাছে উপরের কোড না থাকে (তবে আপনি যা মনে করেন) তবে প্রতিবার আপনি যখন আবেদন করেন arraylist.add()তখন new Object[]তৈরি করতে হবে যা অর্থহীন এবং প্রতিটি বস্তুর যোগ করার জন্য আমরা আকার বাড়িয়ে দেওয়ার জন্য সময় হারাচ্ছি। সুতরাং Object[]নিম্নলিখিত সূত্রের সাথে আকার বাড়ানো ভাল ।
(জেএসএল প্রতিবার ১ টি বাড়ার পরিবর্তে গতিশীলভাবে বর্ধমান অ্যারেলিস্টের জন্য নীচে প্রদত্ত ফোরকাস্টিং সূত্র ব্যবহার করেছে Because কারণ বাড়ার জন্য এটি জেভিএম দ্বারা প্রচেষ্টা লাগে)

int newCapacity = (oldCapacity * 3)/2 + 1;

অ্যারেলিস্ট প্রতিটি এককের জন্য পুনঃস্থাপন করবে নাadd - এটি ইতিমধ্যে অভ্যন্তরীণভাবে কিছু বৃদ্ধি সূত্র ব্যবহার করে। সুতরাং প্রশ্নের উত্তর দেওয়া হয় না।
এএইচ

@ উত্তর আমার উত্তর নেতিবাচক পরীক্ষার জন্য । দয়া করে লাইনের মাঝে পড়ুন। আমি বলেছিলাম "যদি আপনার পুনর্নির্মাণের জন্য উপরে কোড (আপনার মনে হয় এমন কোনও অলগ) না থাকে তবে প্রতিবার যখন আপনি অ্যারেলিস্ট.অডড করেন (তখন) তখন নতুন অবজেক্ট [] তৈরি করতে হবে যা অর্থহীন এবং আমরা সময় হারাচ্ছি।" এবং কোড হয় int newCapacity = (oldCapacity * 3)/2 + 1;যা ArrayList ক্লাসে উপস্থিত। আপনি কি এখনও মনে করেন যে এটি উত্তরহীন?
অমিতজি 15'13

1
আমি এখনও মনে করি এটা উত্তর না হয়: ইন ArrayListamortized পদ্ধতিতে পুনরায় বরাদ্দকরণের মধ্যে সঞ্চালিত হয় কোনো মামলা কোনো প্রাথমিক ধারণক্ষমতা জন্য মান। এবং প্রশ্নটি সম্পর্কে: কেন প্রাথমিক ক্ষমতার জন্য মোটেই একটি মানহীন মান ব্যবহার করবেন? এগুলি ছাড়াও: "লাইনের মধ্যে পড়া" কোনও প্রযুক্তিগত উত্তরে কাঙ্ক্ষিত কিছু নয়। ;-)
এএইচ

@ আঃ আমি এইভাবে উত্তর দিচ্ছি, অ্যারেলিস্টে পুনর্নির্ধারণ প্রক্রিয়া না হলে আমাদের কী হয়েছিল। উত্তরটিও তাই। উত্তরের মনোভাবটি পড়ার চেষ্টা করুন :-)। আমি আরও ভালভাবে জানি অ্যারেলিস্টে প্রাথমিক ক্ষমতার জন্য কোনও মান সহ এমরোটাইজড রিলোকেশনটি কোনও ক্ষেত্রেই ঘটে।
অমিতজি

2

আমি মনে করি প্রতিটি অ্যারেলিস্ট "10" এর একটি ইন ডি ক্ষমতা ক্ষমতা দিয়ে তৈরি করা হয়েছে। যাইহোক, আপনি যদি কনস্ট্রাক্টরের মধ্যে ক্ষমতা নির্ধারণ না করে একটি অ্যারেলিস্ট তৈরি করেন তবে এটি একটি ডিফল্ট মান দিয়ে তৈরি করা হবে।


2

আমি এটি একটি অপ্টিমাইজেশন বলতে চাই। প্রাথমিক ক্ষমতা ছাড়াই অ্যারেলিস্টে 10 ডলার খালি সারি থাকবে এবং আপনি যখন অ্যাড করবেন তখন প্রসারিত হবে।

ঠিক আইটেমের সংখ্যার সাথে একটি তালিকা পেতে আপনাকে ট্রিমটোসাইজ () কল করতে হবে


0

আমার অভিজ্ঞতা অনুসারে ArrayList, পুনর্নির্মাণ ব্যয়গুলি এড়ানোর জন্য প্রাথমিক ক্ষমতা দেওয়া একটি দুর্দান্ত উপায়। তবে এটি একটি সতর্কতা বহন করে। উপরে উল্লিখিত সমস্ত পরামর্শ বলছে যে কেবলমাত্র উপাদানগুলির সংখ্যার মোটামুটি অনুমানের সময় জানা গেলে প্রাথমিক দক্ষতা সরবরাহ করা উচিত। তবে যখন আমরা কোনও ধারণা ছাড়াই প্রাথমিক ক্ষমতা দেওয়ার চেষ্টা করি, তখন মেমরির পরিমাণ সংরক্ষিত এবং অব্যবহৃত হবে waste কারণ তালিকাটি প্রয়োজনীয় সংখ্যক উপাদানগুলিতে পূরণ করার পরে এটি কখনই প্রয়োজন হতে পারে না। আমি যা বলছি তা হচ্ছে, ক্ষমতা বরাদ্দ করার সময় আমরা শুরুতে বাস্তববাদী হতে পারি এবং তারপরে রানটাইমে প্রয়োজনীয় ন্যূনতম ক্ষমতা জানার একটি স্মার্ট উপায় খুঁজে পেতে পারি। অ্যারেলিস্ট নামক একটি পদ্ধতি সরবরাহ করে ensureCapacity(int minCapacity)। তবে তারপরে, একটি স্মার্ট উপায় খুঁজে পেয়েছে ...


0

আমি আদ্যক্ষেত্রের ক্ষমতা ছাড়াই এবং ছাড়াই অ্যারেলিস্টটি পরীক্ষা করে দেখেছি এবং আমি আশ্চর্যজনক ফলাফল পেয়েছি
যখন আমি LOOP_NUMBER 100,000 বা তার চেয়ে কম সেট করি ফলাফলটি হ'ল প্রাথমিক ক্ষমতার সেটিংটি দক্ষ।

list1Sttop-list1Start = 14
list2Sttop-list2Start = 10


কিন্তু আমি যখন LOOP_NUMBER সেট করে 1,000,000 এ ফলাফল পরিবর্তন করে:

list1Stop-list1Start = 40
list2Stop-list2Start = 66


অবশেষে, আমি বুঝতে পারি না এটি কীভাবে কাজ করে ?!
কোডের উদাহরণ:

 public static final int LOOP_NUMBER = 100000;

public static void main(String[] args) {

    long list1Start = System.currentTimeMillis();
    List<Integer> list1 = new ArrayList();
    for (int i = 0; i < LOOP_NUMBER; i++) {
        list1.add(i);
    }
    long list1Stop = System.currentTimeMillis();
    System.out.println("list1Stop-list1Start = " + String.valueOf(list1Stop - list1Start));

    long list2Start = System.currentTimeMillis();
    List<Integer> list2 = new ArrayList(LOOP_NUMBER);
    for (int i = 0; i < LOOP_NUMBER; i++) {
        list2.add(i);
    }
    long list2Stop = System.currentTimeMillis();
    System.out.println("list2Stop-list2Start = " + String.valueOf(list2Stop - list2Start));
}

আমি উইন্ডোজ 8.1 এবং jdk1.7.0_80 এ পরীক্ষা করেছি


1
হাই, দুর্ভাগ্যক্রমে বর্তমান টাইমমিলিস সহনশীলতা একশ মিলি সেকেন্ডের (নির্ভরশীল), যার অর্থ ফলাফল খুব নির্ভরযোগ্য hard আমি এটি সঠিকভাবে করতে কিছু কাস্টম লাইব্রেরি ব্যবহার করার পরামর্শ দেব।
বোগদান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.