जावास्क्रिप्ट में तेजी से स्थिर छँटाई एल्गोरिथ्म कार्यान्वयन


104

मैं एक विशिष्ट कुंजी और दिए गए आदेश (asc / desc) पर छंटनी कर लगभग 200-300 ऑब्जेक्ट्स की एक सरणी को सॉर्ट करना चाह रहा हूं। परिणामों का क्रम सुसंगत और स्थिर होना चाहिए।

उपयोग करने के लिए सबसे अच्छा एल्गोरिथ्म क्या होगा, और क्या आप इसे जावास्क्रिप्ट में लागू करने का एक उदाहरण प्रदान कर सकते हैं?

धन्यवाद!


6
चूंकि कम से कम क्रोम की सरणी सॉर्ट स्थिर नहीं लगती है, इसलिए अंतर्निहित सरणी सॉर्ट पर निर्भर होना आपके लिए कोई विकल्प नहीं है।
नोसरेडना

संक्षेप में: मैं आधुनिक ब्राउज़रों के बीच Array.sort स्थिरता असंगति (मुख्य रूप से क्रोम इस टिप्पणी के समय एक स्थिर प्रकार को लागू नहीं करने के कारण) के कारण एक हाथ लुढ़का हुआ मर्ज प्रकार के साथ गया था। आपकी मदद के लिए सभी को शुक्रिया!
विलियम कैसरिन 15'09

"स्थिर" प्रकार से हमारा क्या मतलब है?
mowwwalker

2
@mowwwalker स्थिर सॉर्ट एक ऐसा सॉर्ट है जिसमें समान सॉर्टिंग वैल्यू वाले सभी आइटम उसी क्रम में छोड़ दिए जाते हैं जैसे कि मूल संग्रह में। en.wikipedia.org/wiki/Sorting_algorithm#Stability
Kornelije Petak

"उपयोग करने के लिए सबसे अच्छा एल्गोरिथ्म क्या है" का जवाब देने के लिए हमें यह जानना होगा कि क्या आपके डेटा में कोई अंतर्निहित संरचना है। नीचे दिए गए बहुत सारे उत्तर केवल मर्ज सॉर्ट या त्वरित सॉर्ट का उपयोग करने के बारे में बात करते हैं, वास्तव में यह डेटा पर निर्भर करता है। यह सिर्फ एक आसान समस्या नहीं है जिसका मैं जवाब दूंगा। Google कुछ छंटाई वाले एल्गोरिदम और उनके बारे में पढ़ने के लिए कि मैं क्या मतलब है। टिमसोर्ट और रेडिक्स सॉर्ट दो अच्छे उदाहरण हैं जिनके बारे में पढ़कर मुझे खुशी होगी।
होगा

जवाबों:


114

गैर-स्थिर सॉर्ट फ़ंक्शन से एक स्थिर सॉर्टिंग प्राप्त करना संभव है।

छांटने से पहले आपको सभी तत्वों की स्थिति मिल जाती है। आपकी सॉर्ट स्थिति में, यदि दोनों तत्व समान हैं, तो आप स्थिति के अनुसार सॉर्ट करते हैं।

टाडा! आपको एक स्थिर प्रकार मिला है।

मैंने अपने ब्लॉग पर इसके बारे में एक लेख लिखा है यदि आप इस तकनीक के बारे में अधिक जानना चाहते हैं और इसे कैसे लागू करना चाहते हैं: http://blog.vjeux.com/2010/javascript/javascript-sorting-table.html


32
क्या आप अपने ब्लॉग को पोस्ट करने और लिंक करने के बजाय यहाँ उत्तर प्रदान कर सकते हैं! धन्यवाद
मोहम्मद करमानी

4
किसी समाधान के लिए लिंक का स्वागत है, लेकिन कृपया सुनिश्चित करें कि आपका उत्तर इसके बिना उपयोगी है: लिंक के चारों ओर संदर्भ जोड़ें ताकि आपके साथी उपयोगकर्ताओं को कुछ पता चले कि यह क्या है और यह क्यों है, तो पृष्ठ के सबसे प्रासंगिक भाग को उद्धृत करें ' लक्ष्य पृष्ठ अनुपलब्ध होने की स्थिति में पुनः लिंक करना। ऐसे लिंक जो किसी लिंक से बहुत कम हैं उन्हें हटाया जा सकता है।
सैमुअल एलवाईई

@VJux चूंकि यह एक लोकप्रिय हो रहा है, क्या आपको इस उत्तर में संबंधित कोड को चिपकाने का मन है? यह बहुत मदद करेगा! धन्यवाद!
विलियम कैसरिन

34

चूंकि आप कुछ स्थिर देख रहे हैं, तो मर्ज को करना चाहिए।

http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/

कोड उपरोक्त वेबसाइट पर पाया जा सकता है:

function mergeSort(arr)
{
    if (arr.length < 2)
        return arr;

    var middle = parseInt(arr.length / 2);
    var left   = arr.slice(0, middle);
    var right  = arr.slice(middle, arr.length);

    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
    var result = [];

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}

संपादित करें:

इस पद के अनुसार , यह ऐरे की तरह दिखता है। कुछ कार्यान्वयन में एक मर्ज प्रकार का उपयोग करता है।


++ मर्ज सॉर्ट मेरा पसंदीदा है। यह सरल और स्थिर है जिसमें कोई सबसे खराब स्थिति नहीं है।
माइक डनलैवी

वेबसाइट का लिंक नीचे है :(
ahitt6345

उदाहरण के लिए एक नई वेबसाइट मिली।
kemiller2002

7
नोट: Array#shiftO (n) समय में काम कर सकता है और इसलिए mergeO (n * n) में आपका।
4esn0k

22

ES2017 में एरो फंक्शंस और डिस्ट्रक्टुरिंग जैसी सुविधाओं का उपयोग करते हुए एक ही चीज़ का थोड़ा छोटा संस्करण:

समारोह

var stableSort = (arr, compare) => arr
  .map((item, index) => ({item, index}))
  .sort((a, b) => compare(a.item, b.item) || a.index - b.index)
  .map(({item}) => item)

यह इनपुट ऐरे को स्वीकार करता है और फ़ंक्शन की तुलना करता है:

stableSort([5,6,3,2,1], (a, b) => a - b)

यह बिल्ट-इन Array.sort () फ़ंक्शन की तरह इन-प्लेस सॉर्ट करने के बजाय नया ऐरे भी देता है ।

परीक्षा

यदि हम निम्न inputसरणी लेते हैं , तो शुरू में इसके अनुसार हल करें weight:

// sorted by weight
var input = [
  { height: 100, weight: 80 },
  { height: 90, weight: 90 },
  { height: 70, weight: 95 },
  { height: 100, weight: 100 },
  { height: 80, weight: 110 },
  { height: 110, weight: 115 },
  { height: 100, weight: 120 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 100, weight: 135 },
  { height: 75, weight: 140 },
  { height: 70, weight: 140 }
]

फिर इसका heightउपयोग करके सॉर्ट करें stableSort:

stableSort(input, (a, b) => a.height - b.height)

का परिणाम:

// Items with the same height are still sorted by weight 
// which means they preserved their relative order.
var stable = [
  { height: 70, weight: 95 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 70, weight: 140 },
  { height: 75, weight: 140 },
  { height: 80, weight: 110 },
  { height: 90, weight: 90 },
  { height: 100, weight: 80 },
  { height: 100, weight: 100 },
  { height: 100, weight: 120 },
  { height: 100, weight: 135 },
  { height: 110, weight: 115 }
]

हालाँकि inputबिल्ट-इन Array.sort()(Chrome / NodeJS में) समान सरणी को छांटना:

input.sort((a, b) => a.height - b.height)

यह दिखाता है:

var unstable = [
  { height: 70, weight: 140 },
  { height: 70, weight: 95 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 75, weight: 140 },
  { height: 80, weight: 110 },
  { height: 90, weight: 90 },
  { height: 100, weight: 100 },
  { height: 100, weight: 80 },
  { height: 100, weight: 135 },
  { height: 100, weight: 120 },
  { height: 110, weight: 115 }
]

साधन

अपडेट करें

Array.prototype.sort अब V8 v7.0 / Chrome 70 में स्थिर है!

पहले, V8 ने 10 से अधिक तत्वों के साथ सरणियों के लिए एक अस्थिर QuickSort का उपयोग किया था। अब, हम स्थिर TimSort एल्गोरिथ्म का उपयोग करते हैं।

स्रोत


1
stableSortसमारोह एक वास्तव में महान हल है!
lhermann

16

मुझे पता है कि इस प्रश्न का उत्तर कुछ समय के लिए दिया गया है, लेकिन मुझे अपने क्लिपबोर्ड में Array और jQuery के लिए एक अच्छा स्थिर मर्ज सॉर्ट कार्यान्वयन है, इसलिए मैं इसे इस उम्मीद में साझा करूंगा कि कुछ भविष्य के खोजकर्ता इसे उपयोगी पा सकते हैं।

यह आपको सामान्य Array.sortकार्यान्वयन की तरह ही अपने स्वयं के तुलना समारोह को निर्दिष्ट करने की अनुमति देता है ।

कार्यान्वयन

// Add stable merge sort to Array and jQuery prototypes
// Note: We wrap it in a closure so it doesn't pollute the global
//       namespace, but we don't put it in $(document).ready, since it's
//       not dependent on the DOM
(function() {

  // expose to Array and jQuery
  Array.prototype.mergeSort = jQuery.fn.mergeSort = mergeSort;

  function mergeSort(compare) {

    var length = this.length,
        middle = Math.floor(length / 2);

    if (!compare) {
      compare = function(left, right) {
        if (left < right)
          return -1;
        if (left == right)
          return 0;
        else
          return 1;
      };
    }

    if (length < 2)
      return this;

    return merge(
      this.slice(0, middle).mergeSort(compare),
      this.slice(middle, length).mergeSort(compare),
      compare
    );
  }

  function merge(left, right, compare) {

    var result = [];

    while (left.length > 0 || right.length > 0) {
      if (left.length > 0 && right.length > 0) {
        if (compare(left[0], right[0]) <= 0) {
          result.push(left[0]);
          left = left.slice(1);
        }
        else {
          result.push(right[0]);
          right = right.slice(1);
        }
      }
      else if (left.length > 0) {
        result.push(left[0]);
        left = left.slice(1);
      }
      else if (right.length > 0) {
        result.push(right[0]);
        right = right.slice(1);
      }
    }
    return result;
  }
})();

उदाहरण उपयोग

var sorted = [
  'Finger',
  'Sandwich',
  'sandwich',
  '5 pork rinds',
  'a guy named Steve',
  'some noodles',
  'mops and brooms',
  'Potato Chip Brand® chips'
].mergeSort(function(left, right) {
  lval = left.toLowerCase();
  rval = right.toLowerCase();

  console.log(lval, rval);
  if (lval < rval)
    return -1;
  else if (lval == rval)
    return 0;
  else
    return 1;
});

sorted == ["5 pork rinds", "a guy named Steve", "Finger", "mops and brooms", "Potato Chip Brand® chips", "Sandwich", "sandwich", "some noodles"];

4
ध्यान दें कि यह मूल प्रकार के साथ है, जो जगह में काम करता है, जिसका अर्थ है कि इसे केवल अंदर नहीं छोड़ा जा सकता है।
एरिक

3
हो सकता है कि स्थिर हो, लेकिन यह विधि मूल की तुलना में लगभग 20 गुना धीमी है array.sort, दोनों तारों और पूर्णांक के लिए यहां परीक्षण देखें -> jsfiddle.net/QC64j
davidkonrad

2
बेशक यह देशी प्रकार की तुलना में धीमा है - यह मूल नहीं है। यह असंभव है। यह भी सच है कि यह एक जगह की तरह नहीं करता है। यह भी असंभव है (सबसे अच्छा मामला यदि आप एक प्रतिलिपि बनाते हैं तो मूल को अधिलेखित करें)। इसके अलावा, जावास्क्रिप्ट की अपनी मूल तरह के व्यवहार के बावजूद एक सॉर्ट की गई प्रति वापस करना अधिक जावास्क्रिप्ट-वाई है। फ़ंक्शन को भी कहा जाता है mergeSortऔर नहीं sort, इसलिए यह प्रतिस्थापन में गिरावट के रूप में इरादा नहीं है। कभी-कभी आपको केवल एक स्थिर मर्ज सॉर्ट की आवश्यकता होती है, उदाहरण के लिए जब कॉलम द्वारा तालिकाओं को सॉर्ट करना।
जस्टिन फोर्स

1
गलत, नोड के मूल प्रकार को जावास्क्रिप्ट में लिखा गया है। यह एक एल्गोरिथ्म के लिए पूरी तरह से संभव है कि देशी प्रकार को गति देने के लिए जावास्क्रिप्ट में प्रोग्राम किया गया है। मैंने पूरी तरह से जावास्क्रिप्ट (एक प्रकार का अनुकूल मर्ज सॉर्ट) में एक छँटाई एल्गोरिथ्म का निर्माण किया जो नोड्स में क्रेमेस / क्रीम / क्रीम देशी क्विकॉर्ट। इस टिप्पणी का उद्देश्य यह बताना है कि जावास्क्रिप्ट के मामले में देशी कोई मायने नहीं रखता है क्योंकि छंटाई एल्गोरिथ्म जावास्क्रिप्ट में लिखी जाती है और कुछ उच्च भाषा में नहीं जैसे कि c ++। प्रमाण यहाँ है: github.com/nodejs/node/blob/master/deps/v8/src/js/array.js
ahitt6345

2
जो कोई इन-प्लेस, ड्रॉप-इन समाधान चाहता है, वह इस कार्यान्वयन से बहुत तेज़ है, मेरा उत्तर देखें
पैट्रिक रॉबर्ट्स

10

इस उत्तर में दिए गए दावे के आधार पर आप मूल कार्यान्वयन की परवाह किए बिना एक स्थिर प्रकार को लागू करने के लिए निम्नलिखित पॉलीफ़िल का उपयोग कर सकते हैं :

// ECMAScript 5 polyfill
Object.defineProperty(Array.prototype, 'stableSort', {
  configurable: true,
  writable: true,
  value: function stableSort (compareFunction) {
    'use strict'

    var length = this.length
    var entries = Array(length)
    var index

    // wrap values with initial indices
    for (index = 0; index < length; index++) {
      entries[index] = [index, this[index]]
    }

    // sort with fallback based on initial indices
    entries.sort(function (a, b) {
      var comparison = Number(this(a[1], b[1]))
      return comparison || a[0] - b[0]
    }.bind(compareFunction))

    // re-map original array to stable sorted values
    for (index = 0; index < length; index++) {
      this[index] = entries[index][1]
    }
    
    return this
  }
})

// usage
const array = Array(500000).fill().map(() => Number(Math.random().toFixed(4)))

const alwaysEqual = () => 0
const isUnmoved = (value, index) => value === array[index]

// not guaranteed to be stable
console.log('sort() stable?', array
  .slice()
  .sort(alwaysEqual)
  .every(isUnmoved)
)
// guaranteed to be stable
console.log('stableSort() stable?', array
  .slice()
  .stableSort(alwaysEqual)
  .every(isUnmoved)
)

// performance using realistic scenario with unsorted big data
function time(arrayCopy, algorithm, compare) {
  var start
  var stop
  
  start = performance.now()
  algorithm.call(arrayCopy, compare)
  stop = performance.now()
  
  return stop - start
}

const ascending = (a, b) => a - b

const msSort = time(array.slice(), Array.prototype.sort, ascending)
const msStableSort = time(array.slice(), Array.prototype.stableSort, ascending)

console.log('sort()', msSort.toFixed(3), 'ms')
console.log('stableSort()', msStableSort.toFixed(3), 'ms')
console.log('sort() / stableSort()', (100 * msSort / msStableSort).toFixed(3) + '%')

ऊपर लागू प्रदर्शन परीक्षण stableSort()चलाने sort()पर, Chrome संस्करण 59-61 की गति का लगभग 57% भाग चलता है ।

.bind(compareFunction)लिपटे हुए अनाम फ़ंक्शन का उपयोग करते हुए प्रत्येक कॉल पर stableSort()एक अनावश्यक स्कोप किए गए संदर्भ से बचने के compareFunctionबजाय 38% से संबंधित प्रदर्शन को इसके संदर्भ में निर्दिष्ट करके।

अपडेट करें

तार्किक लघु-परिचालित करने के लिए बदल दिया गया टर्नरी ऑपरेटर, जो औसत पर बेहतर प्रदर्शन करता है (दक्षता में 2-3% का अंतर करता है)।


5

आपूर्ति की गई फ़ंक्शन को लागू करने के बाद, आपूर्ति की गई सरणी को निम्न प्रकार देते हैं, जब तुलनात्मक फ़ंक्शन रिटर्न देता है तो मूल सूचकांक तुलना को वापस कर देता है 0:

function stableSort(arr, compare) {
    var original = arr.slice(0);

    arr.sort(function(a, b){
        var result = compare(a, b);
        return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
    });

    return arr;
}

नीचे दिए गए उदाहरण, उपनामों के नामों की एक सरणी को समान उपनामों के क्रम को बनाए रखते हैं:

var names = [
	{ surname: "Williams", firstname: "Mary" },
	{ surname: "Doe", firstname: "Mary" }, 
	{ surname: "Johnson", firstname: "Alan" }, 
	{ surname: "Doe", firstname: "John" }, 
	{ surname: "White", firstname: "John" }, 
	{ surname: "Doe", firstname: "Sam" }
]

function stableSort(arr, compare) {
    var original = arr.slice(0);

    arr.sort(function(a, b){
        var result = compare(a, b);
        return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
    });
	
    return arr;
}

stableSort(names, function(a, b) { 
	return a.surname > b.surname ? 1 : a.surname < b.surname ? -1 : 0;
})

names.forEach(function(name) {
	console.log(name.surname + ', ' + name.firstname);
});


सरणी में आदिम प्रकार या डुप्लिकेट तत्वों के लिए स्थिर नहीं है। jQuery.expando.split( "" ).sort( ( a, b ) => 0 ).join( "" ) === jQuery.expando
शहीद

3

यहाँ एक स्थिर कार्यान्वयन है। यह मूल प्रकार का उपयोग करके काम करता है, लेकिन ऐसे मामलों में जहां तत्व समान रूप से तुलना करते हैं, आप मूल सूचकांक स्थिति का उपयोग करके संबंधों को तोड़ते हैं।

function stableSort(arr, cmpFunc) {
    //wrap the arr elements in wrapper objects, so we can associate them with their origional starting index position
    var arrOfWrapper = arr.map(function(elem, idx){
        return {elem: elem, idx: idx};
    });

    //sort the wrappers, breaking sorting ties by using their elements orig index position
    arrOfWrapper.sort(function(wrapperA, wrapperB){
        var cmpDiff = cmpFunc(wrapperA.elem, wrapperB.elem);
        return cmpDiff === 0 
             ? wrapperA.idx - wrapperB.idx
             : cmpDiff;
    });

    //unwrap and return the elements
    return arrOfWrapper.map(function(wrapper){
        return wrapper.elem;
    });
}

एक पूरी तरह से परीक्षण

var res = stableSort([{a:1, b:4}, {a:1, b:5}], function(a, b){
    return a.a - b.a;
});
console.log(res);

एक अन्य जवाब में यह कहा गया है, लेकिन तेह कोडज़ पोस्ट नहीं किया।

लेकिन, यह मेरे बेंचमार्क के अनुसार उपवास नहीं है । मैंने एक मर्ज सॉर्ट को संशोधित करके कस्टम तुलनित्र फ़ंक्शन को स्वीकार किया, और यह बहुत तेज़ था।


क्या आपके बेंचमार्क सही हैं? लगता है, आपका "स्थिर" इनपुट इनपुट सरणी, अन्य प्रकारों को संशोधित नहीं करता है - और, जैसा कि आपने "सेटअप" के दौरान "गिरफ्तार" नहीं किया था, अन्य प्रकार पहले से ही सॉर्ट किए गए सरणियों ...
4esn0k

@ 4esn0k क्या आपने गलत पढ़ा? मैंने कहा कि मेरा स्टेबलसॉर्ट फंक फास्ट नहीं था।
बकरी

@ कटा, आह, क्षमा करें
4esn0k

3

आप Timsort का भी उपयोग कर सकते हैं। यह वास्तव में जटिल एल्गोरिथ्म है (400+ लाइनें, इसलिए यहां कोई स्रोत कोड नहीं है), इसलिए विकिपीडिया का विवरण देखें या मौजूदा जावास्क्रिप्ट कार्यान्वयन में से एक का उपयोग करें:

GPL 3 कार्यान्वयन । Array.prototype.timsort के रूप में पैक किया गया। जावा कोड का एक सटीक फिर से लिखना प्रतीत होता है।

सार्वजनिक डोमेन कार्यान्वयन एक ट्यूटोरियल के रूप में, नमूना कोड केवल पूर्णांक के साथ इसका उपयोग दिखाता है।

Timsort मर्जर्ट और शफ़ल सॉर्ट का एक अत्यधिक अनुकूलित हाइब्रिड है और पायथन और जावा (1.7+) में डिफ़ॉल्ट सॉर्टिंग एल्गोरिथ्म है। यह एक जटिल एल्गोरिथ्म है, क्योंकि यह कई विशेष मामलों के लिए अलग-अलग एल्गोरिदम का उपयोग करता है। लेकिन इसके परिणामस्वरूप यह विभिन्न प्रकार की परिस्थितियों में बहुत तेज है।


1

से एक साधारण से एक mergeSort http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/

var a = [34, 203, 3, 746, 200, 984, 198, 764, 9];

function mergeSort(arr)
{
    if (arr.length < 2)
         return arr;

    var middle = parseInt(arr.length / 2);
    var left   = arr.slice(0, middle);
    var right  = arr.slice(middle, arr.length);

    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
     var result = [];

    while (left.length && right.length) {
         if (left[0] <= right[0]) {
             result.push(left.shift());
         } else {
            result.push(right.shift());
         }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}

console.log(mergeSort(a));

0

मुझे एक अनियंत्रित कॉलम द्वारा बहुआयामी सरणियों को क्रमबद्ध करना होगा, और फिर दूसरे द्वारा। मैं इस फ़ंक्शन को सॉर्ट करने के लिए उपयोग करता हूं:

function sortMDArrayByColumn(ary, sortColumn){

    //Adds a sequential number to each row of the array
    //This is the part that adds stability to the sort
    for(var x=0; x<ary.length; x++){ary[x].index = x;}

    ary.sort(function(a,b){
        if(a[sortColumn]>b[sortColumn]){return 1;}
        if(a[sortColumn]<b[sortColumn]){return -1;}
        if(a.index>b.index){
            return 1;
        }
        return -1;
    });
}

ध्यान दें कि ary.sort कभी भी शून्य नहीं देता है, जो कि "सॉर्ट" फ़ंक्शन के कुछ कार्यान्वयन ऐसे निर्णय लेते हैं जो सही नहीं हो सकते हैं।

यह भी बहुत तेज़ है।


0

यहां बताया गया है कि आप MERGE SORT का उपयोग करते हुए एक प्रोटोटाइप विधि के साथ JS default Array ऑब्जेक्ट को कैसे बढ़ा सकते हैं । यह विधि एक विशिष्ट कुंजी (पहले पैरामीटर) और दिए गए आदेश ('asc' / 'desc' को दूसरे पैरामीटर) पर छाँटने की अनुमति देती है।

Array.prototype.mergeSort = function(sortKey, direction){
  var unsortedArray = this;
  if(unsortedArray.length < 2) return unsortedArray;

  var middle = Math.floor(unsortedArray.length/2);
  var leftSubArray = unsortedArray.slice(0,middle).mergeSort(sortKey, direction);
  var rightSubArray = unsortedArray.slice(middle).mergeSort(sortKey, direction);

  var sortedArray = merge(leftSubArray, rightSubArray);
  return sortedArray;

  function merge(left, right) {
    var combined = [];
    while(left.length>0 && right.length>0){
      var leftValue = (sortKey ? left[0][sortKey] : left[0]);
      var rightValue = (sortKey ? right[0][sortKey] : right[0]);
      combined.push((direction === 'desc' ? leftValue > rightValue : leftValue < rightValue) ? left.shift() : right.shift())
    }
    return combined.concat(left.length ? left : right)
  }
}

आप उपरोक्त स्निपेट को अपने ब्राउज़र कंसोल में डालकर, फिर कोशिश करके खुद को परख सकते हैं:

var x = [2,76,23,545,67,-9,12];
x.mergeSort(); //[-9, 2, 12, 23, 67, 76, 545]
x.mergeSort(undefined, 'desc'); //[545, 76, 67, 23, 12, 2, -9]

या वस्तुओं की एक सरणी में एक विशिष्ट क्षेत्र पर आधारित आदेश:

var y = [
  {startTime: 100, value: 'cat'},
  {startTime: 5, value: 'dog'},
  {startTime: 23, value: 'fish'},
  {startTime: 288, value: 'pikachu'}
]
y.mergeSort('startTime');
y.mergeSort('startTime', 'desc');

0

इसलिए मुझे अपने रिएक्ट + रेडक्स ऐप के लिए एक स्थिर प्रकार की आवश्यकता थी, और वीजेक्स के जवाब ने यहां मेरी मदद की। हालाँकि, मेरा (जेनेरिक) समाधान मुझे अब तक यहां देखे गए अन्य लोगों की तुलना में भिन्न प्रतीत होता है, इसलिए मैं इसे साझा कर रहा हूं यदि किसी और के पास एक मिलान उपयोग-मामला है:

  • मैं वास्तव में केवल sort()एपीआई के समान कुछ करना चाहता हूं, जहां मैं एक तुलनित्र फ़ंक्शन पास कर सकता हूं।
  • कभी-कभी मैं इन-प्लेस को सॉर्ट कर सकता हूं , और कभी-कभी मेरा डेटा अपरिवर्तनीय होता है (क्योंकि Redux) और मुझे इसके बजाय एक सॉर्ट की गई कॉपी चाहिए। इसलिए मुझे प्रत्येक उपयोग-मामले के लिए एक स्थिर छँटाई फ़ंक्शन की आवश्यकता है।
  • ES2015।

मेरा समाधान टाइप टाइप सरणी बनाना है indices, फिर इन इंडिसेस को सॉर्ट -टू- सॉर्ट किए गए सरणी के आधार पर सॉर्ट करने के लिए एक तुलना फ़ंक्शन का उपयोग करें । फिर हम indicesमूल सरणी को सॉर्ट करने के लिए छांटे का उपयोग कर सकते हैं या एकल पास में एक सॉर्ट की गई प्रतिलिपि बना सकते हैं। यदि यह भ्रामक है, तो इस तरह से सोचें: जहां आप सामान्य रूप से एक तुलनात्मक कार्य करेंगे:

(a, b) => { 
  /* some way to compare a and b, returning -1, 0, or 1 */ 
};

अब आप उपयोग के बजाय:

(i, j) => { 
  let a = arrayToBeSorted[i], b = arrayToBeSorted[j]; 
  /* some way to compare a and b, returning -1 or 1 */
  return i - j; // fallback when a == b
}

गति अच्छी है; यह मूल रूप से अंतर्निहित छँटाई एल्गोरिथ्म है, और अंत में दो रैखिक पास है, और सूचक अप्रत्यक्ष उपरि की एक अतिरिक्त परत है।

इस दृष्टिकोण पर प्रतिक्रिया प्राप्त करने में खुशी है। यहाँ इसका पूरा कार्यान्वयन है:

/**
 * - `array`: array to be sorted
 * - `comparator`: closure that expects indices `i` and `j`, and then
 *   compares `array[i]` to `array[j]` in some way. To force stability,
 *   end with `i - j` as the last "comparison".
 * 
 * Example:
 * ```
 *  let array = [{n: 1, s: "b"}, {n: 1, s: "a"}, {n:0, s: "a"}];
 *  const comparator = (i, j) => {
 *    const ni = array[i].n, nj = array[j].n;
 *    return ni < nj ? -1 :
 *      ni > nj ? 1 :
 *        i - j;
 *  };
 *  stableSortInPlace(array, comparator);
 *  // ==> [{n:0, s: "a"}, {n:1, s: "b"}, {n:1, s: "a"}]
 * ```
 */
function stableSortInPlace(array, comparator) {
  return sortFromIndices(array, findIndices(array, comparator));
}

function stableSortedCopy(array, comparator){
  let indices = findIndices(array, comparator);
  let sortedArray = [];
  for (let i = 0; i < array.length; i++){
    sortedArray.push(array[indices[i]]);
  }
  return sortedArray;
}

function findIndices(array, comparator){
  // Assumes we don't have to worry about sorting more than 
  // 4 billion elements; if you know the upper bounds of your
  // input you could replace it with a smaller typed array
  let indices = new Uint32Array(array.length);
  for (let i = 0; i < indices.length; i++) {
    indices[i] = i;
  }
  // after sorting, `indices[i]` gives the index from where
  // `array[i]` should take the value from, so to sort
  // move the value at at `array[indices[i]]` to `array[i]`
  return indices.sort(comparator);
}

// If I'm not mistaken this is O(2n) - each value is moved
// only once (not counting the vacancy temporaries), and 
// we also walk through the whole array once more to check
// for each cycle.
function sortFromIndices(array, indices) {
  // there might be multiple cycles, so we must
  // walk through the whole array to check.
  for (let k = 0; k < array.length; k++) {
    // advance until we find a value in
    // the "wrong" position
    if (k !== indices[k]) {
      // create vacancy to use "half-swaps" trick,
      // props to Andrei Alexandrescu
      let v0 = array[k];
      let i = k;
      let j = indices[k];
      while (j !== k) {
        // half-swap next value
        array[i] = array[j];
        // array[i] now contains the value it should have,
        // so we update indices[i] to reflect this
        indices[i] = i;
        // go to next index
        i = j;
        j = indices[j];
      }
      // put original array[k] back in
      // and update indices
      array[i] = v0;
      indices[i] = i;
    }
  }
  return array;
}

0

मुझे पता है कि यह बहुत उत्तर दिया गया है। मैं बस किसी के लिए एक त्वरित टीएस कार्यान्वयन को आगे बढ़ाना चाहता था जो यहां की तलाश में था।

export function stableSort<T>( array: T[], compareFn: ( a: T, b: T ) => number ): T[] {
    const indices = array.map( ( x: T, i: number ) => ( { element: x, index: i } ) );

    return indices.sort( ( a, b ) => {
        const order = compareFn( a.element, b.element );
        return order === 0 ? a.index - b.index : order;
    } ).map( x => x.element );
}

विधि अब इन-प्लेस नहीं चलती है, जैसा कि देशी सॉर्ट करता है। मैं यह भी बताना चाहता हूं कि यह सबसे कुशल नहीं है। यह आदेश O (n) के दो छोरों को जोड़ता है। हालांकि सॉर्ट ओ (एन लॉग (एन)) सबसे अधिक संभावना है, इसलिए यह उससे कम है।

बताए गए कुछ समाधान अधिक प्रदर्शन करने वाले हैं, सोचा कि यह कम कोड हो सकता है, आंतरिक का उपयोग भी कर सकता है Array.prototype.sort

(एक जावास्क्रिप्ट समाधान के लिए, सभी प्रकार हटा दें)


0

V8 देव ब्लॉग और caniuse.com के अनुसार Array.sortआधुनिक ब्राउज़रों में कल्पना द्वारा पहले से ही आवश्यक है, इसलिए आपको अपने समाधान को रोल करने की आवश्यकता नहीं है। एकमात्र अपवाद मैं देख सकता हूं एज, जो जल्द ही क्रोमियम से आगे बढ़ना चाहिए और साथ ही इसका समर्थन करना चाहिए।


0

function sort(data){
    var result=[];
    var array = data;
    const array2=data;
    const len=array2.length;
    for(var i=0;i<=len-1;i++){
    var min = Math.min.apply(Math,array)
    result.push(min);
    var index=array.indexOf(min)
    array.splice(index,1);
    }
    return result;
}   
sort([9,8,5,7,9,3,9,243,4,5,6,3,4,2,4,7,4,9,55,66,33,66]);


-1

सॉर्टिंग सॉर्ट मर्ज सॉर्ट की तुलना में तेज़ है (यह ओ (एन) समय में प्रदर्शन करता है) और यह पूर्णांकों पर उपयोग के लिए है।

Math.counting_sort = function (m) {
    var i
    var j
    var k
    var step
    var start
    var Output
    var hash
    k = m.length
    Output = new Array ()
    hash = new Array ()
    // start at lowest possible value of m
    start = 0
    step = 1
    // hash all values
    i = 0
    while ( i < k ) {
        var _m = m[i]
        hash [_m] = _m
        i = i + 1
    }
    i = 0
    j = start
    // find all elements within x
    while ( i < k ) {
        while ( j != hash[j] ) {
            j = j + step
        }
        Output [i] = j
        i = i + 1
        j = j + step
    }
    return Output
}

उदाहरण:

var uArray = new Array ()<br/>
var sArray = new Array ()<br/><br/>
uArray = [ 10,1,9,2,8,3,7,4,6,5 ]<br/>
sArray = Math.counting_sort ( uArray ) // returns a sorted array

12
कुछ बातों को कहा जाना चाहिए: 1. गिनती प्रकार केवल एक घने संख्या स्थान में अच्छी तरह से काम करता है। (सरणी को क्रमबद्ध करने का प्रयास करें [1, 2e9, 1e9]) 2. छोरों के लिए छोरों के रूप में न लिखें। 3. बेतरतीब ढंग से मैथ नेमस्पेस में चीजें न जोड़ें। 4. आप अर्धविराम से दोस्ती करने पर विचार कर सकते हैं।
डोमी

इसके अलावा, अगर सरणी में डुप्लिकेट मान हैं, तो यह हमेशा के लिए चलेगा। उदाहरण के लिए, array [3, 1, 3]हैश करने के लिए [undefined, 1, undefined, 3]। हमें दो गैर-अपरिभाषित मूल्य मिलते हैं, जबकि एल्गोरिदम को उम्मीद है कि उनमें से तीन होंगे।
एमकेपीएस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.