এটি গোলাকার দুই।
প্রথম দফায় আমি যা নিয়ে এসেছিলাম তারপরে আমি ডোমেনটি দিয়ে আমার মন্তব্যে কিছুটা আরও আবদ্ধ মন্তব্যগুলি পুনরায় পড়ি।
সুতরাং এখানে ইউনিট পরীক্ষার সহজতম সংস্করণ এটি দেখায় যা এটি অন্যান্য সংস্করণের উপর ভিত্তি করে কাজ করে।
প্রথম অ-সমবর্তী সংস্করণ:
import java.util.LinkedHashMap;
import java.util.Map;
public class LruSimpleCache<K, V> implements LruCache <K, V>{
Map<K, V> map = new LinkedHashMap ( );
public LruSimpleCache (final int limit) {
map = new LinkedHashMap <K, V> (16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
return super.size() > limit;
}
};
}
@Override
public void put ( K key, V value ) {
map.put ( key, value );
}
@Override
public V get ( K key ) {
return map.get(key);
}
//For testing only
@Override
public V getSilent ( K key ) {
V value = map.get ( key );
if (value!=null) {
map.remove ( key );
map.put(key, value);
}
return value;
}
@Override
public void remove ( K key ) {
map.remove ( key );
}
@Override
public int size () {
return map.size ();
}
public String toString() {
return map.toString ();
}
}
আসল পতাকাটি গেটস এবং পুটসের অ্যাক্সেসকে ট্র্যাক করবে। জাভাডোকস দেখুন। কনস্ট্রাক্টরের সত্যিকারের পতাকা ছাড়াই সরানোএডলস্ট্রি এন্ট্রি কেবল একটি ফিফো ক্যাশে প্রয়োগ করবে (ফিফোর নীচে নোটগুলি দেখুন এবং রিলিজএলডেস্ট্রি)।
এখানে পরীক্ষাটি প্রমাণ করে যে এটি একটি এলআরইউ ক্যাশে হিসাবে কাজ করে:
public class LruSimpleTest {
@Test
public void test () {
LruCache <Integer, Integer> cache = new LruSimpleCache<> ( 4 );
cache.put ( 0, 0 );
cache.put ( 1, 1 );
cache.put ( 2, 2 );
cache.put ( 3, 3 );
boolean ok = cache.size () == 4 || die ( "size" + cache.size () );
cache.put ( 4, 4 );
cache.put ( 5, 5 );
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
ok |= cache.getSilent ( 4 ) == 4 || die ();
ok |= cache.getSilent ( 5 ) == 5 || die ();
cache.get ( 2 );
cache.get ( 3 );
cache.put ( 6, 6 );
cache.put ( 7, 7 );
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
ok |= cache.getSilent ( 4 ) == null || die ();
ok |= cache.getSilent ( 5 ) == null || die ();
if ( !ok ) die ();
}
এখন সমবর্তী সংস্করণের জন্য ...
org.boon.cache প্যাকেজ;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LruSimpleConcurrentCache<K, V> implements LruCache<K, V> {
final CacheMap<K, V>[] cacheRegions;
private static class CacheMap<K, V> extends LinkedHashMap<K, V> {
private final ReadWriteLock readWriteLock;
private final int limit;
CacheMap ( final int limit, boolean fair ) {
super ( 16, 0.75f, true );
this.limit = limit;
readWriteLock = new ReentrantReadWriteLock ( fair );
}
protected boolean removeEldestEntry ( final Map.Entry<K, V> eldest ) {
return super.size () > limit;
}
@Override
public V put ( K key, V value ) {
readWriteLock.writeLock ().lock ();
V old;
try {
old = super.put ( key, value );
} finally {
readWriteLock.writeLock ().unlock ();
}
return old;
}
@Override
public V get ( Object key ) {
readWriteLock.writeLock ().lock ();
V value;
try {
value = super.get ( key );
} finally {
readWriteLock.writeLock ().unlock ();
}
return value;
}
@Override
public V remove ( Object key ) {
readWriteLock.writeLock ().lock ();
V value;
try {
value = super.remove ( key );
} finally {
readWriteLock.writeLock ().unlock ();
}
return value;
}
public V getSilent ( K key ) {
readWriteLock.writeLock ().lock ();
V value;
try {
value = this.get ( key );
if ( value != null ) {
this.remove ( key );
this.put ( key, value );
}
} finally {
readWriteLock.writeLock ().unlock ();
}
return value;
}
public int size () {
readWriteLock.readLock ().lock ();
int size = -1;
try {
size = super.size ();
} finally {
readWriteLock.readLock ().unlock ();
}
return size;
}
public String toString () {
readWriteLock.readLock ().lock ();
String str;
try {
str = super.toString ();
} finally {
readWriteLock.readLock ().unlock ();
}
return str;
}
}
public LruSimpleConcurrentCache ( final int limit, boolean fair ) {
int cores = Runtime.getRuntime ().availableProcessors ();
int stripeSize = cores < 2 ? 4 : cores * 2;
cacheRegions = new CacheMap[ stripeSize ];
for ( int index = 0; index < cacheRegions.length; index++ ) {
cacheRegions[ index ] = new CacheMap<> ( limit / cacheRegions.length, fair );
}
}
public LruSimpleConcurrentCache ( final int concurrency, final int limit, boolean fair ) {
cacheRegions = new CacheMap[ concurrency ];
for ( int index = 0; index < cacheRegions.length; index++ ) {
cacheRegions[ index ] = new CacheMap<> ( limit / cacheRegions.length, fair );
}
}
private int stripeIndex ( K key ) {
int hashCode = key.hashCode () * 31;
return hashCode % ( cacheRegions.length );
}
private CacheMap<K, V> map ( K key ) {
return cacheRegions[ stripeIndex ( key ) ];
}
@Override
public void put ( K key, V value ) {
map ( key ).put ( key, value );
}
@Override
public V get ( K key ) {
return map ( key ).get ( key );
}
//For testing only
@Override
public V getSilent ( K key ) {
return map ( key ).getSilent ( key );
}
@Override
public void remove ( K key ) {
map ( key ).remove ( key );
}
@Override
public int size () {
int size = 0;
for ( CacheMap<K, V> cache : cacheRegions ) {
size += cache.size ();
}
return size;
}
public String toString () {
StringBuilder builder = new StringBuilder ();
for ( CacheMap<K, V> cache : cacheRegions ) {
builder.append ( cache.toString () ).append ( '\n' );
}
return builder.toString ();
}
}
আমি দেখতে পাচ্ছি কেন আমি প্রথমে অ-সমবর্তী সংস্করণটি কভার করি। লক কনটেন্ট হ্রাস করার জন্য উপরেরগুলি কিছু স্ট্রিপ তৈরি করার চেষ্টা করে। সুতরাং আমরা এটি কীটি নিয়েছি এবং তারপরে আসল ক্যাশে সন্ধান করার জন্য সেই হ্যাশটি সন্ধান করব। এটি আপনার কী হ্যাশ অ্যালগরিদমকে কতটা ভালভাবে ছড়িয়েছে তার উপর নির্ভর করে ন্যায্য পরিমাণ ত্রুটির মধ্যে সীমাবদ্ধ আকারের প্রস্তাবনা / মোটামুটি অনুমানের আরও বেশি করে তোলে।
একযোগে সংস্করণ সম্ভবত কাজ করে তা দেখানোর জন্য এখানে পরীক্ষা দেওয়া হচ্ছে। :) (আগুনের অধীনে পরীক্ষাটি আসল উপায় হবে)।
public class SimpleConcurrentLRUCache {
@Test
public void test () {
LruCache <Integer, Integer> cache = new LruSimpleConcurrentCache<> ( 1, 4, false );
cache.put ( 0, 0 );
cache.put ( 1, 1 );
cache.put ( 2, 2 );
cache.put ( 3, 3 );
boolean ok = cache.size () == 4 || die ( "size" + cache.size () );
cache.put ( 4, 4 );
cache.put ( 5, 5 );
puts (cache);
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
ok |= cache.getSilent ( 4 ) == 4 || die ();
ok |= cache.getSilent ( 5 ) == 5 || die ();
cache.get ( 2 );
cache.get ( 3 );
cache.put ( 6, 6 );
cache.put ( 7, 7 );
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
cache.put ( 8, 8 );
cache.put ( 9, 9 );
ok |= cache.getSilent ( 4 ) == null || die ();
ok |= cache.getSilent ( 5 ) == null || die ();
puts (cache);
if ( !ok ) die ();
}
@Test
public void test2 () {
LruCache <Integer, Integer> cache = new LruSimpleConcurrentCache<> ( 400, false );
cache.put ( 0, 0 );
cache.put ( 1, 1 );
cache.put ( 2, 2 );
cache.put ( 3, 3 );
for (int index =0 ; index < 5_000; index++) {
cache.get(0);
cache.get ( 1 );
cache.put ( 2, index );
cache.put ( 3, index );
cache.put(index, index);
}
boolean ok = cache.getSilent ( 0 ) == 0 || die ();
ok |= cache.getSilent ( 1 ) == 1 || die ();
ok |= cache.getSilent ( 2 ) != null || die ();
ok |= cache.getSilent ( 3 ) != null || die ();
ok |= cache.size () < 600 || die();
if ( !ok ) die ();
}
}
এটিই সর্বশেষ পোস্ট .. এটি একটি এলএফইউ হিসাবে এলআরইউ ক্যাশে নয় বলে আমি প্রথম পোস্টটি মুছলাম।
আমি ভেবেছিলাম এটিকে আরেকবার যাব। আমি স্ট্যান্ডার্ড জেডি কে ডাব্লু / ও খুব বেশি প্রয়োগকরণ ব্যবহার করে একটি এলআরইউ ক্যাশের সহজতম সংস্করণ নিয়ে আসার চেষ্টা করছিলাম।
এখানে আমি যা নিয়ে এসেছি তা এখানে। আমি এবং এলআরইউয়ের পরিবর্তে এলএফইউ প্রয়োগ করায় আমার প্রথম প্রয়াস কিছুটা বিপর্যয় হয়েছিল এবং তারপরে আমি এতে ফিফও এবং এলআরইউ সমর্থন যুক্ত করেছি ... এবং তখন আমি বুঝতে পারি এটি একটি দৈত্য হয়ে উঠছে। তারপরে আমি আমার বন্ধু জনের সাথে কথা বলতে শুরু করলাম যিনি সবে আগ্রহী ছিলেন এবং আমি তখন গভীর দৈর্ঘ্যে বর্ণনা করেছিলাম কীভাবে আমি কীভাবে এলএফইউ, এলআরইউ এবং ফিফো বাস্তবায়িত করেছি এবং আপনি কীভাবে এটি একটি সহজ এনইউএম আর্গ দিয়ে স্যুইচ করতে পারবেন এবং আমি বুঝতে পেরেছিলাম যে আমি সত্যিই চেয়েছিলাম একটি সাধারণ এলআরইউ ছিল। সুতরাং আমার কাছ থেকে আগের পোস্টটি উপেক্ষা করুন, এবং আপনি যদি একটি এনআরএমের মাধ্যমে পরিবর্তনযোগ্য কোনও এলআরইউ / এলএফইউ / ফিফো ক্যাশে দেখতে চান তবে আমাকে জানতে দিন ... না? ঠিক আছে .. এখানে তিনি যান।
কেবল জেডিকে ব্যবহার করে সবচেয়ে সহজতম এলআরইউ। আমি একসাথে সংস্করণ এবং একটি সহ-সংস্করণ উভয়ই প্রয়োগ করেছি implemented
আমি একটি সাধারণ ইন্টারফেস তৈরি করেছি (এটি ন্যূনতমতা তাই সম্ভবত আপনার পছন্দ মতো কয়েকটি বৈশিষ্ট্য অনুপস্থিত তবে এটি আমার ব্যবহারের ক্ষেত্রে কাজ করে তবে আপনি যদি XYZ বৈশিষ্ট্যটি দেখতে চান তবে আমাকে জানাতে দিন ... আমি কোড লিখতে বাঁচি)) ।
public interface LruCache<KEY, VALUE> {
void put ( KEY key, VALUE value );
VALUE get ( KEY key );
VALUE getSilent ( KEY key );
void remove ( KEY key );
int size ();
}
আপনি অবাক হতে পারেন কি getSilent কি। আমি এটি পরীক্ষার জন্য ব্যবহার করি। getSilent কোনও আইটেমের LRU স্কোর পরিবর্তন করে না।
প্রথমে অসমাপ্ত এক ....
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
public class LruCacheNormal<KEY, VALUE> implements LruCache<KEY,VALUE> {
Map<KEY, VALUE> map = new HashMap<> ();
Deque<KEY> queue = new LinkedList<> ();
final int limit;
public LruCacheNormal ( int limit ) {
this.limit = limit;
}
public void put ( KEY key, VALUE value ) {
VALUE oldValue = map.put ( key, value );
/*If there was already an object under this key,
then remove it before adding to queue
Frequently used keys will be at the top so the search could be fast.
*/
if ( oldValue != null ) {
queue.removeFirstOccurrence ( key );
}
queue.addFirst ( key );
if ( map.size () > limit ) {
final KEY removedKey = queue.removeLast ();
map.remove ( removedKey );
}
}
public VALUE get ( KEY key ) {
/* Frequently used keys will be at the top so the search could be fast.*/
queue.removeFirstOccurrence ( key );
queue.addFirst ( key );
return map.get ( key );
}
public VALUE getSilent ( KEY key ) {
return map.get ( key );
}
public void remove ( KEY key ) {
/* Frequently used keys will be at the top so the search could be fast.*/
queue.removeFirstOccurrence ( key );
map.remove ( key );
}
public int size () {
return map.size ();
}
public String toString() {
return map.toString ();
}
}
queue.removeFirstOccurrence যদি আপনি একটি বড় ক্যাশে আছে একটি সম্ভাব্য ব্যয়বহুল অপারেশন। লিংকডলিস্টকে উদাহরণ হিসাবে নেওয়া যেতে পারে এবং অপসারণের কাজগুলি খুব বেশি দ্রুত এবং আরও সামঞ্জস্যপূর্ণ করার জন্য উপাদান থেকে নোডের মধ্যে একটি বিপরীত অনুসন্ধানের হ্যাশ ম্যাপ যুক্ত করতে পারে। আমিও শুরু করেছিলাম, কিন্তু তখন বুঝতে পেরেছিলাম এর দরকার নেই। কিন্তু সম্ভবত...
যখন করা বলা হয়, কী সারিতে যোগ হয়। যখন পাবেন বলা হয়, কী সেটি সরানো এবং কিউ শীর্ষে পুনরায় যোগ করা হয়েছে।
যদি আপনার ক্যাশেটি ছোট হয় এবং কোনও আইটেম তৈরি করা ব্যয়বহুল হয় তবে এটি ভাল ক্যাশে হওয়া উচিত। যদি আপনার ক্যাশেটি সত্যিই বড় হয় তবে লিনিয়ার সন্ধানটি বোতলের ঘা হতে পারে বিশেষত আপনার যদি ক্যাশের গরম অঞ্চল না থাকে। তীব্র গরম দাগগুলি যত তীব্র হবে, গরম আইটেম হিসাবে রৈখিক অনুসন্ধান তত দ্রুত রৈখিক অনুসন্ধানের শীর্ষে থাকে। যাইহোক ... এটি আরও দ্রুত যাওয়ার জন্য যা প্রয়োজন তা হল আরেকটি লিংকডলিস্ট লিখুন যাতে একটি অপসারণ অপারেশন রয়েছে যা অপসারণের জন্য নোড লুকিংয়ের বিপরীত উপাদান রয়েছে, তারপরে অপসারণ হ্যাশ ম্যাপ থেকে কোনও কী মুছে ফেলার মতো দ্রুত হবে।
আপনার যদি 1000 টি আইটেমের নীচে ক্যাশে থাকে তবে এটি ভাল কাজ করবে।
এটির ক্রিয়াকলাপগুলি কার্যকরভাবে দেখানোর জন্য এটি একটি সাধারণ পরীক্ষা।
public class LruCacheTest {
@Test
public void test () {
LruCache<Integer, Integer> cache = new LruCacheNormal<> ( 4 );
cache.put ( 0, 0 );
cache.put ( 1, 1 );
cache.put ( 2, 2 );
cache.put ( 3, 3 );
boolean ok = cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 0 ) == 0 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
cache.put ( 4, 4 );
cache.put ( 5, 5 );
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 0 ) == null || die ();
ok |= cache.getSilent ( 1 ) == null || die ();
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
ok |= cache.getSilent ( 4 ) == 4 || die ();
ok |= cache.getSilent ( 5 ) == 5 || die ();
if ( !ok ) die ();
}
}
শেষ এলআরইউ ক্যাশেটি একক থ্রেডযুক্ত ছিল এবং দয়া করে এটি একটি সিঙ্ক্রোনাইজড কিছুতে মোড়ানো করবেন না ...
একসাথে সংস্করণে ছুরিকাঘাত এখানে।
import java.util.Deque;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentLruCache<KEY, VALUE> implements LruCache<KEY,VALUE> {
private final ReentrantLock lock = new ReentrantLock ();
private final Map<KEY, VALUE> map = new ConcurrentHashMap<> ();
private final Deque<KEY> queue = new LinkedList<> ();
private final int limit;
public ConcurrentLruCache ( int limit ) {
this.limit = limit;
}
@Override
public void put ( KEY key, VALUE value ) {
VALUE oldValue = map.put ( key, value );
if ( oldValue != null ) {
removeThenAddKey ( key );
} else {
addKey ( key );
}
if (map.size () > limit) {
map.remove ( removeLast() );
}
}
@Override
public VALUE get ( KEY key ) {
removeThenAddKey ( key );
return map.get ( key );
}
private void addKey(KEY key) {
lock.lock ();
try {
queue.addFirst ( key );
} finally {
lock.unlock ();
}
}
private KEY removeLast( ) {
lock.lock ();
try {
final KEY removedKey = queue.removeLast ();
return removedKey;
} finally {
lock.unlock ();
}
}
private void removeThenAddKey(KEY key) {
lock.lock ();
try {
queue.removeFirstOccurrence ( key );
queue.addFirst ( key );
} finally {
lock.unlock ();
}
}
private void removeFirstOccurrence(KEY key) {
lock.lock ();
try {
queue.removeFirstOccurrence ( key );
} finally {
lock.unlock ();
}
}
@Override
public VALUE getSilent ( KEY key ) {
return map.get ( key );
}
@Override
public void remove ( KEY key ) {
removeFirstOccurrence ( key );
map.remove ( key );
}
@Override
public int size () {
return map.size ();
}
public String toString () {
return map.toString ();
}
}
প্রধান পার্থক্য হ্যাশম্যাপের পরিবর্তে সাম্প্রতিক হ্যাশম্যাপ ব্যবহার এবং লক ব্যবহার (আমি সিঙ্ক্রোনাইজড হয়ে যেতে পারতাম, তবে ...)।
আমি এটি আগুনের নীচে পরীক্ষা করে দেখিনি, তবে এটি একটি সাধারণ এলআরইউ ক্যাশে বলে মনে হচ্ছে যা ব্যবহারের ক্ষেত্রে 80% এর মধ্যে কার্যকর হতে পারে যেখানে আপনার একটি সাধারণ এলআরইউ মানচিত্র প্রয়োজন।
আপনি কেন লাইব্রেরি a, b, বা c ব্যবহার করবেন না তা বাদ দিয়ে আমি প্রতিক্রিয়া স্বাগত জানাই। আমি সবসময় একটি লাইব্রেরি ব্যবহার না করার কারণ হ'ল আমি সবসময় প্রতিটি যুদ্ধের ফাইল 80MB হওয়া চাই না এবং আমি লাইব্রেরি লিখি যাতে আমি জায়গায় ভাল সমাধানের সাথে লাইবগুলিকে প্লাগ-সক্ষম করতে পারি এবং কেউ প্লাগ করতে পারে - তারা চাইলে অন্য ক্যাশে সরবরাহকারী। :) আমি কখনই জানি না যে কারওর জন্য কখন পেয়ারা বা এহচেচে বা অন্য কোনও কিছুর প্রয়োজন হতে পারে আমি সেগুলি অন্তর্ভুক্ত করতে চাই না, তবে আমি যদি ক্যাচিং প্লাগ-সক্ষম করি তবে আমি সেগুলিও বাদ দেব না।
নির্ভরতা হ্রাসের নিজস্ব পুরষ্কার রয়েছে। এটিকে কীভাবে আরও সহজ বা দ্রুত বা উভয় হিসাবে তৈরি করা যায় সে সম্পর্কে আমি কিছু প্রতিক্রিয়া পেতে পছন্দ করি।
এছাড়াও যদি কেউ যেতে প্রস্তুত জানেন ...
ঠিক আছে .. আমি জানি আপনি কী ভাবছেন ... কেন তিনি কেবল লিঙ্কডহ্যাশম্যাপ থেকে অপসারণের প্রাচীনতম এন্ট্রি ব্যবহার করেন না, এবং ভালই আমার উচিত কিন্তু .... তবে .. তবে .. এটি কোনও ফিফোর হবে আরআরইউ নয় এবং আমরা ছিলাম একটি এলআরইউ বাস্তবায়নের চেষ্টা করছি।
Map<KEY, VALUE> map = new LinkedHashMap<KEY, VALUE> () {
@Override
protected boolean removeEldestEntry ( Map.Entry<KEY, VALUE> eldest ) {
return this.size () > limit;
}
};
এই পরীক্ষাটি উপরের কোডটির জন্য ব্যর্থ হয় ...
cache.get ( 2 );
cache.get ( 3 );
cache.put ( 6, 6 );
cache.put ( 7, 7 );
ok |= cache.size () == 4 || die ( "size" + cache.size () );
ok |= cache.getSilent ( 2 ) == 2 || die ();
ok |= cache.getSilent ( 3 ) == 3 || die ();
ok |= cache.getSilent ( 4 ) == null || die ();
ok |= cache.getSilent ( 5 ) == null || die ();
সুতরাং এখানে রিলিজএলডেস্ট্রি ব্যবহার করে একটি দ্রুত এবং নোংরা ফিফো ক্যাশে রয়েছে।
import java.util.*;
public class FifoCache<KEY, VALUE> implements LruCache<KEY,VALUE> {
final int limit;
Map<KEY, VALUE> map = new LinkedHashMap<KEY, VALUE> () {
@Override
protected boolean removeEldestEntry ( Map.Entry<KEY, VALUE> eldest ) {
return this.size () > limit;
}
};
public LruCacheNormal ( int limit ) {
this.limit = limit;
}
public void put ( KEY key, VALUE value ) {
map.put ( key, value );
}
public VALUE get ( KEY key ) {
return map.get ( key );
}
public VALUE getSilent ( KEY key ) {
return map.get ( key );
}
public void remove ( KEY key ) {
map.remove ( key );
}
public int size () {
return map.size ();
}
public String toString() {
return map.toString ();
}
}
ফিফো দ্রুত। আশেপাশে কোনও খোঁজ নেই। আপনি একটি এলআরইউয়ের সামনে একটি ফিফোর সামনে দাঁড়াতে পারেন এবং এটি বেশিরভাগ হট এন্ট্রিগুলি বেশ সুন্দরভাবে পরিচালনা করবে। আরও ভাল এলআরইউর জন্য নোড বৈশিষ্ট্যটিতে সেই বিপরীত উপাদানগুলির প্রয়োজন হবে।
যাইহোক ... এখন যেহেতু আমি কিছু কোড লিখেছি, আমাকে অন্য উত্তরগুলি দিয়ে যেতে দাও এবং আমি কী মিস করেছি তা দেখুন ... আমি প্রথমবার সেগুলি স্ক্যান করেছিলাম।
O(1)
প্রয়োজনীয় সংস্করণ: stackoverflow.com/questions/23772102/...