जावा में क्रमबद्ध सरणी सूची


85

मैं चकित हूं कि मुझे इसका त्वरित जवाब नहीं मिल रहा है। मैं अनिवार्य रूप से जावा में एक डेटास्ट्रक्चर की तलाश कर रहा हूं जो java.util.Listइंटरफ़ेस को लागू करता है, लेकिन जो अपने सदस्यों को क्रमबद्ध क्रम में संग्रहीत करता है। मुझे पता है कि आप एक सामान्य ArrayListका उपयोग कर सकते हैं और Collections.sort()उस पर उपयोग कर सकते हैं , लेकिन मेरे पास एक ऐसा परिदृश्य है जहां मैं कभी-कभार अपनी सूची से सदस्यों को जोड़ रहा हूं और अक्सर इसे प्राप्त करना चाहता हूं और हर बार जब मैं मामले में एक सदस्य को पुनः प्राप्त करता हूं तो मुझे इसे सॉर्ट करना नहीं पड़ता है नया जोड़ा गया है। क्या कोई मुझे ऐसी चीज की ओर इंगित कर सकता है जो जेडीके या यहां तक ​​कि 3 पार्टी पुस्तकालयों में मौजूद है?

संपादित करें : डेटास्ट्रक्चर को डुप्लिकेट को संरक्षित करने की आवश्यकता होगी।

ANSWER का सारांश : मुझे यह सब बहुत दिलचस्प लगा और बहुत कुछ सीखा। Aioobe विशेष रूप से मेरी आवश्यकताओं को प्राप्त करने की कोशिश में उनकी दृढ़ता के लिए उल्लेख योग्य है (मुख्य रूप से एक सॉर्ट किए गए java.util। कार्यान्वयन जो डुप्लिकेट का समर्थन करता है)। मैंने उनके उत्तर को सबसे सटीक माना है, जो मैंने पूछा था और जो मैंने चाहा था उसके निहितार्थ पर भड़काने वाला सबसे अच्छा विचार था, भले ही मैंने पूछा कि वास्तव में मुझे क्या चाहिए था।

मैंने सूची इंटरफेस में खुद से झूठ और एक इंटरफेस में वैकल्पिक तरीकों की अवधारणा के साथ जो समस्या पूछी। जावदोक को उद्धृत करने के लिए:

इस इंटरफ़ेस के उपयोगकर्ता का सटीक नियंत्रण है कि सूची में प्रत्येक तत्व कहां डाला गया है।

एक सॉर्ट की गई सूची में सम्मिलित करने से प्रविष्टि बिंदु पर सटीक नियंत्रण नहीं होता है। फिर, आपको यह सोचना होगा कि आप कुछ तरीकों को कैसे संभालेंगे। addउदाहरण के लिए लें :

सार्वजनिक बूलियन ऐड (ऑब्जेक्ट ओ)

 Appends the specified element to the end of this list (optional operation).

अब आप या तो 1 की असहज स्थिति में रह गए हैं) अनुबंध को तोड़ना और ऐड 2 के सॉर्ट किए गए संस्करण को लागू करना) addसूची के अंत में एक तत्व जोड़ने की अनुमति देना, आपके सॉर्ट किए गए ऑर्डर को तोड़ना 3) addबाहर फेंकना (इसके वैकल्पिक रूप में) फेंककर UnsupportedOperationExceptionए और एक अन्य विधि को लागू करना जो क्रमबद्ध क्रम में आइटम जोड़ता है।

विकल्प 3 शायद सबसे अच्छा है, लेकिन मुझे लगता है कि यह एक ऐड-वे विधि है जिसका आप उपयोग नहीं कर सकते हैं और एक अन्य सॉर्ट किया गया तरीका है जो इंटरफ़ेस में नहीं है।

अन्य संबंधित समाधान (कोई विशेष क्रम में नहीं):

  • java.util.PyerityQueue जो मैंने जो मांगा था उसकी तुलना में शायद मैं सबसे ज्यादा करीब हूं। एक कतार मेरे मामले में वस्तुओं के संग्रह की सबसे सटीक परिभाषा नहीं है, लेकिन कार्यात्मक रूप से यह वह सब कुछ करता है जिसकी मुझे आवश्यकता है।
  • net.sourceforge.nite.util.SortedList । हालाँकि, यह कार्यान्वयन add(Object obj)विधि में सॉर्टिंग को लागू करके सूची इंटरफ़ेस के अनुबंध को तोड़ता है और विचित्र रूप से इसके लिए कोई प्रभाव विधि नहीं है add(int index, Object obj)। आम सहमति बताती है throw new UnsupportedOperationException()कि इस परिदृश्य में एक बेहतर विकल्प हो सकता है।
  • अमरूद का ट्रीमल्टीसेट एक सेट कार्यान्वयन जो डुप्लिकेट का समर्थन करता है
  • ca.odell.glazedlists.SortedList यह वर्ग अपने javadoc में चेतावनी के साथ आता है:Warning: This class breaks the contract required by List

4
यदि आप कभी-कभी सम्मिलित करते हैं और अक्सर पढ़ते हैं तो सम्मिलन के दौरान इसे क्यों नहीं छाँटा जाए?
सर्ग

जवाबों:


62

न्यूनतम समाधान

यहाँ एक "न्यूनतम" समाधान है।

class SortedArrayList<T> extends ArrayList<T> {

    @SuppressWarnings("unchecked")
    public void insertSorted(T value) {
        add(value);
        Comparable<T> cmp = (Comparable<T>) value;
        for (int i = size()-1; i > 0 && cmp.compareTo(get(i-1)) < 0; i--)
            Collections.swap(this, i, i-1);
    }
}

आवेषण रैखिक समय में चलता है, लेकिन यह वही होगा जो आप किसी भी ArrayList का उपयोग करके प्राप्त करेंगे (सम्मिलित तत्व के दाईं ओर सभी तत्वों को एक या दूसरे तरीके से स्थानांतरित करना होगा)।

ClassCastException में कुछ गैर-तुलनीय परिणाम सम्मिलित करना। (यह दृष्टिकोण द्वारा उठाए गए है PriorityQueueसाथ ही: । एक प्राथमिकता कतार प्राकृतिक आदेश पर निर्भर भी गैर तुलनीय वस्तुओं की प्रविष्टि (ऐसा करने ClassCastException में हो सकता है) की अनुमति नहीं देता )

अधिभावी List.add

ध्यान दें कि एक क्रमबद्ध तरीके से तत्वों को सम्मिलित करने के लिए ओवरराइडिंग List.add(या List.addAllउस मामले के लिए) इंटरफ़ेस विनिर्देश का प्रत्यक्ष उल्लंघन होगा । आप क्या कर सकते हैं, फेंकने के लिए इस पद्धति को ओवरराइड करना हैUnsupportedOperationException

के डॉक्स से List.add:

boolean add(E e)
    इस सूची के अंत (वैकल्पिक संचालन) के लिए निर्दिष्ट तत्व को लागू करता है।

एक ही तर्क के दोनों संस्करणों के लिए लागू होता है add, के दोनों संस्करणों addAllऔर set। (सभी जो सूची इंटरफ़ेस के अनुसार वैकल्पिक संचालन हैं।)


कुछ परीक्षण

SortedArrayList<String> test = new SortedArrayList<String>();

test.insertSorted("ddd");    System.out.println(test);
test.insertSorted("aaa");    System.out.println(test);
test.insertSorted("ccc");    System.out.println(test);
test.insertSorted("bbb");    System.out.println(test);
test.insertSorted("eee");    System.out.println(test);

.... प्रिंट:

[ddd]
[aaa, ddd]
[aaa, ccc, ddd]
[aaa, bbb, ccc, ddd]
[aaa, bbb, ccc, ddd, eee]

एक अच्छी शुरुआत, लेकिन कॉलिंग ऐड, या ऐडऑल एक असंगत फैशन में सदस्यों को जोड़ देगा।
क्रिस नाइट

हाँ। कुछ भी लेकिन उन्हें सूची में शामिल करना सूची-इंटरफ़ेस का सीधा उल्लंघन होगा। देखिये मेरा अपडेटेड जवाब।
aioobe

@aioobe अच्छा बिंदु। लेकिन एक इंटरफ़ेस विधि एक कोड गंध का असमर्थित ऑपरेशन नहीं है? उचित तरीका यह हो सकता है कि ArrayList का विस्तार न करें लेकिन सूची को लागू करें लेकिन फिर भी शायद सूची केवल इस उद्देश्य के लिए नहीं थी। Javadoc से सूची के लिए: The user of this interface has precise control over where in the list each element is insertedजो क्रमबद्ध तरीके से तत्वों को सम्मिलित करने के लिए सबसे अच्छा विवरण नहीं है और आपको अभी भी add(int index, Object obj)इंटरफ़ेस विधि से निपटना है । ये समस्याएँ शायद समझाती हैं कि सूची को एक क्रमबद्ध तरीके से लागू क्यों नहीं किया गया है।
क्रिस नाइट

खैर, ऑपरेशन एक कारण के लिए वैकल्पिक है। अगर मुझे .addSortedArrayList पर एक UnsupportedExceptionOperation मिला तो मुझे आश्चर्य नहीं होगा । हां, ऐड के दोनों संस्करणों के लिए एक ही तर्क लागू होता है, एड और ऑल के दोनों संस्करण। (सभी जो सूची इंटरफ़ेस के अनुसार वैकल्पिक संचालन हैं।)
aioobe

आह, मुझे नहीं पता था कि वे वैकल्पिक ऑपरेशन थे। प्लॉट मोटा हो जाता है ...;)
क्रिस नाइट

10

का उपयोग करें java.util.PriorityQueue


7
यह कोई सूची नहीं है, अर्थात कोई यादृच्छिक पहुँच नहीं है।
थिलो

1
यह कतार आधारित प्राथमिकता है हीप सूची लागू नहीं करता है।
zengr

3
बेशक, एक सूची के साथ जो क्रम को बनाए रखता है, अनुक्रमित हर समय बदलते रहते हैं, इसलिए यादृच्छिक पहुंच की वैसे भी आवश्यकता नहीं है।
थिलो

5
@ क्वेर्स्की, ध्यान दें कि सटीक उत्तर हमेशा सबसे अच्छा उत्तर नहीं होता है, या उत्तर ओपी वास्तव में होता है।
एनियोबॉय

3
प्राथमिकता कतार पुनरावृत्ति पर क्रमबद्ध अनुदान नहीं देती है।
मार्कोरोसी

6

SortedList पर एक नज़र है

यह वर्ग क्रमबद्ध सूची को लागू करता है। यह एक तुलनित्र के साथ निर्मित होता है जो दो वस्तुओं की तुलना कर सकता है और तदनुसार वस्तुओं को क्रमबद्ध कर सकता है। जब आप सूची में कोई ऑब्जेक्ट जोड़ते हैं, तो उसे सही जगह पर डाला जाता है। ऑब्जेक्ट जो तुलनित्र के अनुसार समान हैं, इस सूची में उस क्रम में होंगे जो उन्हें इस सूची में जोड़ा गया था। केवल उन वस्तुओं को जोड़ें जो तुलनित्र तुलना कर सकते हैं।


जब सूची में पहले से ही ऑब्जेक्ट्स होते हैं जो तुलनित्र के अनुसार समान होते हैं, तो नई ऑब्जेक्ट को इन अन्य ऑब्जेक्ट्स के तुरंत बाद डाला जाएगा।


5
यह अच्छा लग रहा है, लेकिन यह भी छोटी लग रही है: AddAll के दोनों संस्करणों में से कोई भी ओवरराइड नहीं है, इसलिए सूची उन लोगों को कॉल करने से पहले ही समाप्त हो जाएगी।
टॉम एंडरसन

3
और जोड़ें विधि "कोई प्रभाव नहीं है"। यदि इसका उपयोग नहीं किया जा सकता है, तो इसे UnsupportedOperationException को फेंकना चाहिए।
थिलो

@ टोम एंडरसन @ थिलो, आप दोनों से सहमत हैं।
जिगर जोशी

1
दिलचस्प है, लेकिन मैं भविष्य में किसी का उपयोग कर रहा हूं addAll()और यह सोच रहा हूं कि यह सभी तत्वों को हल कर दिया जाएगा। UnsupportedOperationException के साथ भी सहमत हैं।
क्रिस नाइट

1
इस सूची के अतिरिक्त समय की जटिलता क्या है?
श्रीविनायको


5

Aioobe का दृष्टिकोण जाने का मार्ग है। मैं हालांकि उसके समाधान पर निम्नलिखित सुधार का सुझाव देना चाहूंगा।

class SortedList<T> extends ArrayList<T> {

    public void insertSorted(T value) {
        int insertPoint = insertPoint(value);
        add(insertPoint, value);
    }

    /**
     * @return The insert point for a new value. If the value is found the insert point can be any
     * of the possible positions that keeps the collection sorted (.33 or 3.3 or 33.).
     */
    private int insertPoint(T key) {
        int low = 0;
        int high = size() - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable<? super T> midVal = (Comparable<T>) get(mid);
            int cmp = midVal.compareTo(key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else {
                return mid; // key found
            }
        }

        return low;  // key not found
    }
}

बड़ी सूचियों का उपयोग करते समय aioobe का घोल बहुत धीमा हो जाता है। इस तथ्य का उपयोग करते हुए कि सूची को क्रमबद्ध किया गया है, हमें बाइनरी खोज का उपयोग करके नए मूल्यों के लिए सम्मिलित बिंदु खोजने की अनुमति देता है।

मैं भी इनहेरिटेंस पर रचना का उपयोग करूंगा, की तर्ज पर कुछ

SortedList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

4

सूची आमतौर पर उस क्रम को संरक्षित करती है जिसमें आइटम जोड़े जाते हैं। क्या आपको निश्चित रूप से एक सूची की आवश्यकता है , या आपके लिए एक सॉर्ट किया गया सेट (जैसे TreeSet<E>) ठीक होगा? असल में, क्या आपको डुप्लिकेट को संरक्षित करने की आवश्यकता है?


2
धन्यवाद जॉन, लेकिन मुझे डुप्लिकेट को संरक्षित करने की आवश्यकता है
क्रिस नाइट


1

आप ArrayList को उपवर्गित कर सकते हैं, और किसी भी तत्व के जुड़ने के बाद Collections.sort (इस) को कॉल कर सकते हैं - आपको ऐसा करने के लिए ऐड के दो संस्करणों और ऐडऑल के दो को ओवरराइड करना होगा।

प्रदर्शन एक बेहतर कार्यान्वयन के रूप में अच्छा नहीं होगा जो सही जगह पर तत्वों को सम्मिलित करता है, लेकिन यह काम करेगा। यदि सूची के अलावा दुर्लभ है, तो सूची में सभी परिचालनों पर परिशोधित लागत कम होनी चाहिए।


1

बस इस तरह एक नया वर्ग बनाएं:

public class SortedList<T> extends ArrayList<T> {

private final Comparator<? super T> comparator;

public SortedList() {
    super();
    this.comparator = null;
}

public SortedList(Comparator<T> comparator) {
    super();
    this.comparator = comparator;
}

@Override
public boolean add(T item) {
    int index = comparator == null ? Collections.binarySearch((List<? extends Comparable<? super T>>)this, item) :
            Collections.binarySearch(this, item, comparator);
    if (index < 0) {
        index = index * -1 - 2;
    }
    super.add(index+1, item);
    return true;
}

@Override
public void add(int index, T item) {
    throw new UnsupportedOperationException("'add' with an index is not supported in SortedArrayList");
}

@Override
public boolean addAll(Collection<? extends T> items) {
    boolean allAdded = true;
    for (T item : items) {
        allAdded = allAdded && add(item);
    }
    return allAdded;
}

@Override
public boolean addAll(int index, Collection<? extends T> items) {
    throw new UnsupportedOperationException("'addAll' with an index is not supported in SortedArrayList");
}

}

आप इसे इस तरह से परख सकते हैं:

    List<Integer> list = new SortedArrayList<>((Integer i1, Integer i2) -> i1.compareTo(i2));
    for (Integer i : Arrays.asList(4, 7, 3, 8, 9, 25, 20, 23, 52, 3)) {
        list.add(i);
    }
    System.out.println(list);

0

मुझे लगता है कि SortedSets / Lists और 'normal' सॉर्टेबल संग्रह के बीच का चुनाव निर्भर करता है, चाहे आपको केवल प्रस्तुति के उद्देश्यों के लिए या रनटाइम के दौरान लगभग हर बिंदु पर छंटनी की आवश्यकता हो। एक सॉर्ट किए गए संग्रह का उपयोग करना बहुत अधिक महंगा हो सकता है क्योंकि छँटाई हर बार की जाती है जब आप एक तत्व सम्मिलित करते हैं।

यदि आप JDK में संग्रह का विकल्प नहीं चुन सकते हैं, तो आप Apache Commons Collection पर एक नज़र डाल सकते हैं


0

चूंकि वर्तमान में प्रस्तावित कार्यान्वयन जो संग्रह एपीआई को तोड़कर एक क्रमबद्ध सूची को लागू करते हैं, उनके पास एक पेड़ या कुछ इसी तरह का कार्यान्वयन होता है, मैं उत्सुक था कि ट्रीपाउप पर आधारित कार्यान्वयन कैसे होगा। (जब से TreeSet TreeMap पर भी आधार करता है, विशिष्ट)

अगर किसी को इसमें दिलचस्पी है, तो भी, वह बेझिझक इसे देख सकता है:

TreeList

कोर लाइब्रेरी का इसका हिस्सा , आप इसे मावेन की निर्भरता के माध्यम से जोड़ सकते हैं। (अपाचे लाइसेंस)

वर्तमान में कार्यान्वयन अमरूद SortedMultiSet और अपाचे कॉमन्स पुस्तकालय के ट्रीलिस्ट की तुलना में समान स्तर पर काफी अच्छी तरह से तुलना करता है।

लेकिन मुझे ख़ुशी होगी अगर केवल और केवल मैं ही क्रियान्वयन का परीक्षण करूँगा यह सुनिश्चित करने के लिए कि मुझे कुछ महत्वपूर्ण याद नहीं है।

सादर!


0

मुझे भी यही समस्या थी। इसलिए मैंने java.util.TreeMap का सोर्स कोड लिया और IndexedTreeMap लिखा । यह मेरे स्वयं के अनुक्रमित NavigableMap को लागू करता है :

public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
   K exactKey(int index);
   Entry<K, V> exactEntry(int index);
   int keyIndex(K k);
}

कार्यान्वयन लाल-काले पेड़ में नोड वज़न को अद्यतन करने पर आधारित है जब इसे बदल दिया जाता है। वजन एक दिए गए नोड के नीचे बच्चे के नोड्स की संख्या है, प्लस एक - स्व। उदाहरण के लिए जब एक पेड़ को बाईं ओर घुमाया जाता है:

    private void rotateLeft(Entry<K, V> p) {
    if (p != null) {
        Entry<K, V> r = p.right;

        int delta = getWeight(r.left) - getWeight(p.right);
        p.right = r.left;
        p.updateWeight(delta);

        if (r.left != null) {
            r.left.parent = p;
        }

        r.parent = p.parent;


        if (p.parent == null) {
            root = r;
        } else if (p.parent.left == p) {
            delta = getWeight(r) - getWeight(p.parent.left);
            p.parent.left = r;
            p.parent.updateWeight(delta);
        } else {
            delta = getWeight(r) - getWeight(p.parent.right);
            p.parent.right = r;
            p.parent.updateWeight(delta);
        }

        delta = getWeight(p) - getWeight(r.left);
        r.left = p;
        r.updateWeight(delta);

        p.parent = r;
    }
  }

updateWeight बस जड़ तक वजन अद्यतन:

   void updateWeight(int delta) {
        weight += delta;
        Entry<K, V> p = parent;
        while (p != null) {
            p.weight += delta;
            p = p.parent;
        }
    }

और जब हमें सूचकांक द्वारा तत्व को खोजने की आवश्यकता है, तो कार्यान्वयन है जो भार का उपयोग करता है:

public K exactKey(int index) {
    if (index < 0 || index > size() - 1) {
        throw new ArrayIndexOutOfBoundsException();
    }
    return getExactKey(root, index);
}

private K getExactKey(Entry<K, V> e, int index) {
    if (e.left == null && index == 0) {
        return e.key;
    }
    if (e.left == null && e.right == null) {
        return e.key;
    }
    if (e.left != null && e.left.weight > index) {
        return getExactKey(e.left, index);
    }
    if (e.left != null && e.left.weight == index) {
        return e.key;
    }
    return getExactKey(e.right, index - (e.left == null ? 0 : e.left.weight) - 1);
}

इसके अलावा एक कुंजी के सूचकांक को खोजने में बहुत काम आता है:

    public int keyIndex(K key) {
    if (key == null) {
        throw new NullPointerException();
    }
    Entry<K, V> e = getEntry(key);
    if (e == null) {
        throw new NullPointerException();
    }
    if (e == root) {
        return getWeight(e) - getWeight(e.right) - 1;//index to return
    }
    int index = 0;
    int cmp;
    index += getWeight(e.left);

    Entry<K, V> p = e.parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        while (p != null) {
            cmp = cpr.compare(key, p.key);
            if (cmp > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    } else {
        Comparable<? super K> k = (Comparable<? super K>) key;
        while (p != null) {
            if (k.compareTo(p.key) > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    }
    return index;
}

आप इस काम का परिणाम http://code.google.com/p/indexed-tree-map/ पर पा सकते हैं

ट्रीसेट / ट्रीपैप (साथ ही अनुक्रमित-ट्री-मैप प्रोजेक्ट से उनके अनुक्रमित समकक्ष) डुप्लिकेट कुंजियों की अनुमति नहीं देते हैं, तो आप मानों की एक सरणी के लिए 1 कुंजी का उपयोग कर सकते हैं। यदि आपको डुप्लिकेट के साथ SortedSet की आवश्यकता है, तो सरणियों के रूप में मानों के साथ TreeMap का उपयोग करें। मैं ऐसा ही करना चाहूंगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.