JavaRush /جاوا بلاگ /Random-UR /نظریہ اور عمل میں الگورتھم کو چھانٹنا
Viacheslav
سطح

نظریہ اور عمل میں الگورتھم کو چھانٹنا

گروپ میں شائع ہوا۔
چھانٹنا اشیاء پر کی جانے والی سرگرمیوں یا اعمال کی بنیادی اقسام میں سے ایک ہے۔ بچپن میں بھی بچوں کو ترتیب دینا سکھایا جاتا ہے، ان کی سوچ کی نشوونما ہوتی ہے۔ کمپیوٹر اور پروگرام بھی اس سے مستثنیٰ نہیں ہیں۔ الگورتھم کی بہت بڑی قسمیں ہیں۔ میرا مشورہ ہے کہ آپ دیکھیں کہ وہ کیا ہیں اور وہ کیسے کام کرتے ہیں۔ اس کے علاوہ، اگر ایک دن آپ سے انٹرویو میں ان میں سے کسی ایک کے بارے میں پوچھا جائے تو کیا ہوگا؟
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 1

تعارف

عناصر کو چھانٹنا الگورتھم کے ان زمروں میں سے ایک ہے جس کی ایک ڈویلپر کو عادت ڈالنی چاہیے۔ اگر کسی زمانے میں، جب میں پڑھتا تھا، کمپیوٹر سائنس کو اتنی سنجیدگی سے نہیں لیا جاتا تھا، تو اب اسکول میں انہیں الگورتھم ترتیب دینے اور سمجھنے کے قابل ہونا چاہیے۔ بنیادی الگورتھم، سب سے آسان، کو ایک لوپ کا استعمال کرتے ہوئے لاگو کیا جاتا ہے for۔ قدرتی طور پر، عناصر کے مجموعے کو ترتیب دینے کے لیے، مثال کے طور پر، ایک صف، آپ کو کسی نہ کسی طرح اس مجموعہ کو عبور کرنے کی ضرورت ہے۔ مثال کے طور پر:
int[] array = {10, 2, 10, 3, 1, 2, 5};
for (int i = 0; i < array.length; i++) {
	System.out.println(array[i]);
}
آپ کوڈ کے اس ٹکڑے کے بارے میں کیا کہہ سکتے ہیں؟ ہمارے پاس ایک لوپ ہے جس میں ہم انڈیکس ویلیو ( int i) کو 0 سے آخری عنصر میں تبدیل کرتے ہیں۔ درحقیقت، ہم صرف ہر عنصر کو صف میں لیتے ہیں اور اس کے مواد کو پرنٹ کرتے ہیں۔ صف میں جتنے زیادہ عناصر ہوں گے، کوڈ کو عمل میں لانے میں اتنا ہی زیادہ وقت لگے گا۔ یعنی، اگر n عناصر کی تعداد ہے، n=10 کے ساتھ پروگرام n=5 کے مقابلے میں 2 گنا زیادہ وقت لے گا۔ جب ہمارے پروگرام میں ایک لوپ ہوتا ہے، تو عملدرآمد کا وقت خطی طور پر بڑھ جاتا ہے: جتنے زیادہ عناصر، عملدرآمد اتنا ہی طویل ہوتا ہے۔ یہ پتہ چلتا ہے کہ اوپر کوڈ کا الگورتھم لکیری وقت (n) میں چلتا ہے۔ ایسے معاملات میں، "الگورتھم پیچیدگی" کو O(n) کہا جاتا ہے۔ اس اشارے کو "بڑا O" یا "asymptotic برتاؤ" بھی کہا جاتا ہے۔ لیکن آپ آسانی سے "الگورتھم کی پیچیدگی" کو یاد رکھ سکتے ہیں۔
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 2

سب سے آسان چھانٹنا (بلبلے کی ترتیب)

تو، ہمارے پاس ایک صف ہے اور اس پر اعادہ کر سکتے ہیں۔ زبردست. آئیے اب اسے صعودی ترتیب میں ترتیب دینے کی کوشش کرتے ہیں۔ ہمارے لیے اس کا کیا مطلب ہے؟ اس کا مطلب ہے کہ دو عناصر (مثال کے طور پر، a=6، b=5) دیئے گئے، ہمیں a اور b کو تبدیل کرنا چاہیے اگر a b سے بڑا ہے (اگر a > b)۔ انڈیکس کے لحاظ سے مجموعہ کے ساتھ کام کرتے وقت ہمارے لیے اس کا کیا مطلب ہے (جیسا کہ ایک صف کا معاملہ ہے)؟ اس کا مطلب یہ ہے کہ اگر انڈیکس a والا عنصر انڈیکس b والے عنصر سے بڑا ہے، (array[a] > array[b])، تو ایسے عناصر کو تبدیل کرنا ضروری ہے۔ جگہوں کو تبدیل کرنے کو اکثر سویپ کہا جاتا ہے۔ جگہوں کو تبدیل کرنے کے مختلف طریقے ہیں۔ لیکن ہم سادہ، واضح اور یاد رکھنے میں آسان کوڈ استعمال کرتے ہیں:
private void swap(int[] array, int ind1, int ind2) {
    int tmp = array[ind1];
    array[ind1] = array[ind2];
    array[ind2] = tmp;
}
اب ہم مندرجہ ذیل لکھ سکتے ہیں:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {
		swap(array, i, i-1);
	}
}
System.out.println(Arrays.toString(array));
جیسا کہ ہم دیکھ سکتے ہیں، عناصر نے واقعی جگہ بدل دی ہے۔ ہم نے ایک عنصر کے ساتھ آغاز کیا، کیونکہ... اگر صف صرف ایک عنصر پر مشتمل ہو، تو اظہار 1 <1 درست نہیں آئے گا اور اس طرح ہم ایک عنصر کے ساتھ یا ان کے بغیر کسی صف کے معاملات سے خود کو محفوظ رکھیں گے، اور کوڈ بہتر نظر آئے گا۔ لیکن ہماری آخری صف کو ویسے بھی ترتیب نہیں دیا گیا ہے، کیونکہ... سب کو ایک پاس میں ترتیب دینا ممکن نہیں ہے۔ ہمیں ایک اور لوپ شامل کرنا پڑے گا جس میں ہم ایک ایک کرکے پاسز کریں گے جب تک کہ ہم ترتیب شدہ صف حاصل نہ کریں:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
boolean needIteration = true;
while (needIteration) {
	needIteration = false;
	for (int i = 1; i < array.length; i++) {
		if (array[i] < array[i - 1]) {
			swap(array, i, i-1);
			needIteration = true;
		}
	}
}
System.out.println(Arrays.toString(array));
تو ہماری پہلی چھانٹی نے کام کیا۔ ہم بیرونی لوپ ( while) میں اعادہ کرتے ہیں جب تک کہ ہم یہ فیصلہ نہ کر لیں کہ مزید تکرار کی ضرورت نہیں ہے۔ پہلے سے طے شدہ طور پر، ہر نئی تکرار سے پہلے، ہم فرض کرتے ہیں کہ ہماری صف کو ترتیب دیا گیا ہے، اور ہم مزید اعادہ نہیں کرنا چاہتے۔ لہذا، ہم ترتیب وار عناصر کے ذریعے جاتے ہیں اور اس مفروضے کو چیک کرتے ہیں۔ لیکن اگر عناصر ترتیب سے باہر ہیں، تو ہم عناصر کو تبدیل کرتے ہیں اور سمجھتے ہیں کہ ہمیں یقین نہیں ہے کہ عناصر اب صحیح ترتیب میں ہیں۔ لہذا، ہم ایک اور تکرار کرنا چاہتے ہیں۔ مثال کے طور پر، [3، 5، 2]۔ 5 تین سے زیادہ ہے، سب کچھ ٹھیک ہے۔ لیکن 2 5 سے کم ہے۔ تاہم، [3، 2، 5] ایک اور پاس کی ضرورت ہے، کیونکہ 3> 2 اور انہیں تبدیل کرنے کی ضرورت ہے۔ چونکہ ہم ایک لوپ کے اندر ایک لوپ کا استعمال کرتے ہیں، یہ پتہ چلتا ہے کہ ہمارے الگورتھم کی پیچیدگی بڑھ جاتی ہے. n عناصر کے ساتھ یہ n * n بن جاتا ہے، یعنی O(n^2)۔ اس پیچیدگی کو چوکور کہا جاتا ہے۔ جیسا کہ ہم سمجھتے ہیں، ہم بالکل نہیں جان سکتے کہ کتنی تکرار کی ضرورت ہوگی۔ الگورتھم پیچیدگی کے اشارے کا مقصد بڑھتی ہوئی پیچیدگی کے رجحان کو ظاہر کرنا ہے، بدترین صورت۔ جب عناصر n کی تعداد میں تبدیلی آتی ہے تو چلنے کا وقت کتنا بڑھ جائے گا۔ بلبلا کی ترتیب سب سے آسان اور غیر موثر قسموں میں سے ایک ہے۔ اسے بعض اوقات "احمقانہ چھانٹی" بھی کہا جاتا ہے۔ متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 3

انتخاب کی ترتیب

ایک اور قسم انتخاب کی ترتیب ہے۔ اس میں چوکور پیچیدگی بھی ہے، لیکن بعد میں اس پر مزید۔ تو خیال آسان ہے۔ ہر پاس سب سے چھوٹے عنصر کو منتخب کرتا ہے اور اسے شروع میں منتقل کرتا ہے۔ اس صورت میں، ہر نئے پاس کو دائیں طرف جا کر شروع کریں، یعنی پہلا پاس - پہلے عنصر سے، دوسرا پاس - دوسرے سے۔ یہ اس طرح نظر آئے گا:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	int minInd = left;
	for (int i = left; i < array.length; i++) {
		if (array[i] < array[minInd]) {
			minInd = i;
		}
	}
	swap(array, left, minInd);
}
System.out.println(Arrays.toString(array));
یہ چھانٹنا غیر مستحکم ہے، کیونکہ ایک جیسے عناصر (خصوصیت کے نقطہ نظر سے جس کے ذریعے ہم عناصر کو ترتیب دیتے ہیں) اپنی پوزیشن تبدیل کر سکتے ہیں۔ ویکیپیڈیا کے مضمون میں ایک اچھی مثال دی گئی ہے: ترتیب_بائی انتخاب ۔ متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 4

داخل کرنے کی ترتیب

داخل کرنے کی ترتیب میں چوکور پیچیدگی بھی ہوتی ہے، کیونکہ ہمارے پاس پھر سے ایک لوپ کے اندر ایک لوپ ہوتا ہے۔ یہ انتخاب کی ترتیب سے کیسے مختلف ہے؟ یہ ترتیب "مستحکم" ہے۔ اس کا مطلب ہے کہ ایک جیسے عناصر اپنی ترتیب کو تبدیل نہیں کریں گے۔ ان خصوصیات کے لحاظ سے یکساں ہے جس کے ذریعے ہم ترتیب دیتے ہیں۔
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	// Retrieve the value of the element
	int value = array[left];
	// Move through the elements that are before the pulled element
	int i = left - 1;
	for (; i >= 0; i--) {
		// If a smaller value is pulled out, move the larger element further
		if (value < array[i]) {
			array[i + 1] = array[i];
		} else {
			// If the pulled element is larger, stop
			break;
		}
	}
	// Insert the extracted value into the freed space
	array[i + 1] = value;
}
System.out.println(Arrays.toString(array));
متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 5

شٹل ترتیب

آسان قسموں میں، ایک اور ہے - شٹل چھانٹنا۔ لیکن مجھے شٹل کی قسم زیادہ پسند ہے۔ مجھے ایسا لگتا ہے کہ ہم خلائی شٹل کے بارے میں شاذ و نادر ہی بات کرتے ہیں، اور شٹل زیادہ دوڑتی ہے۔ لہذا، یہ تصور کرنا آسان ہے کہ خلاء میں شٹل کیسے بھیجے جاتے ہیں۔ یہاں اس الگورتھم کے ساتھ ایک تعلق ہے۔ الگورتھم کا جوہر کیا ہے؟ الگورتھم کا جوہر یہ ہے کہ ہم بائیں سے دائیں تکرار کرتے ہیں، اور عناصر کو تبدیل کرتے وقت، ہم باقی تمام عناصر کو چیک کرتے ہیں جو یہ دیکھنے کے لیے پیچھے رہ گئے ہیں کہ آیا سویپ کو دہرانے کی ضرورت ہے۔
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {
		swap(array, i, i - 1);
		for (int z = i - 1; (z - 1) >= 0; z--) {
			if (array[z] < array[z - 1]) {
				swap(array, z, z - 1);
			} else {
				break;
			}
		}
	}
}
System.out.println(Arrays.toString(array));
متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 6

شیل کی ترتیب

ایک اور سادہ قسم شیل کی ترتیب ہے۔ اس کا جوہر بلبلے کی ترتیب سے ملتا جلتا ہے، لیکن ہر تکرار میں ہمارے مقابلے کے عناصر کے درمیان فرق ہوتا ہے۔ ہر تکرار اسے آدھا کر دیا جاتا ہے۔ یہاں عمل درآمد کی ایک مثال ہے:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
// Calculate the gap between the checked elements
int gap = array.length / 2;
// As long as there is a difference between the elements
while (gap >= 1) {
    for (int right = 0; right < array.length; right++) {
        // Shift the right pointer until we can find one that
        // there won't be enough space between it and the element before it
       for (int c = right - gap; c >= 0; c -= gap) {
           if (array[c] > array[c + gap]) {
               swap(array, c, c + gap);
           }
        }
    }
    // Recalculate the gap
    gap = gap / 2;
}
System.out.println(Arrays.toString(array));
متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کی چھانٹی - 7

ترتیب کو ضم کریں۔

اشارہ کردہ سادہ قسموں کے علاوہ، زیادہ پیچیدہ قسمیں ہیں۔ مثال کے طور پر، ترتیب کو ضم کریں۔ سب سے پہلے، تکرار ہماری مدد کے لیے آئے گی۔ دوم، ہماری پیچیدگی اب چوکور نہیں رہے گی، جیسا کہ ہم عادی ہیں۔ اس الگورتھم کی پیچیدگی لوگارتھمک ہے۔ O(n log n) کے بطور لکھا گیا۔ تو آئیے یہ کرتے ہیں۔ سب سے پہلے، آئیے چھانٹنے کے طریقہ کار پر ایک تکراری کال لکھیں:
public static void mergeSort(int[] source, int left, int right) {
        // Choose a separator, i.e. split the input array in half
        int delimiter = left + ((right - left) / 2) + 1;
        // Execute this function recursively for the two halves (if we can split(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
}
اب، آئیے اس میں ایک اہم کارروائی شامل کریں۔ یہاں عمل درآمد کے ساتھ ہمارے سپر طریقہ کی ایک مثال ہے:
public static void mergeSort(int[] source, int left, int right) {
        // Choose a separator, i.e. split the input array in half
        int delimiter = left + ((right - left) / 2) + 1;
        // Execute this function recursively for the two halves (if we can split(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
        // Create a temporary array with the desired size
        int[] buffer = new int[right - left + 1];
        // Starting from the specified left border, go through each element
        int cursor = left;
        for (int i = 0; i < buffer.length; i++) {
            // We use the delimeter to point to the element from the right side
            // If delimeter > right, then there are no unadded elements left on the right side
            if (delimiter > right || source[cursor] > source[delimiter]) {
                buffer[i] = source[cursor];
                cursor++;
            } else {
                buffer[i] = source[delimiter];
                delimiter++;
            }
        }
        System.arraycopy(buffer, 0, source, left, buffer.length);
}
آئیے کال کرکے مثال چلائیں mergeSort(array, 0, array.length-1)۔ جیسا کہ آپ دیکھ سکتے ہیں، جوہر اس حقیقت پر آتا ہے کہ ہم ان پٹ کے طور پر ایک سرنی لیتے ہیں جو ترتیب دینے والے حصے کے آغاز اور اختتام کی نشاندہی کرتا ہے۔ جب چھانٹنا شروع ہوتا ہے، یہ صف کا آغاز اور اختتام ہوتا ہے۔ اگلا ہم حد بندی کا حساب لگاتے ہیں - تقسیم کرنے والے کی پوزیشن۔ اگر تقسیم کرنے والا 2 حصوں میں تقسیم ہو سکتا ہے، تو ہم ان حصوں کے لیے تکراری چھانٹی کہتے ہیں جن میں ڈیوائیڈر نے صف کو تقسیم کیا ہے۔ ہم ایک اضافی بفر اری تیار کرتے ہیں جس میں ہم ترتیب شدہ حصے کو منتخب کرتے ہیں۔ اس کے بعد، ہم کرسر کو ترتیب دینے کے لیے علاقے کے شروع میں رکھتے ہیں اور ہم نے تیار کردہ خالی صف کے ہر عنصر سے گزرنا شروع کر دیا ہے اور اسے چھوٹے عناصر سے بھر دیتے ہیں۔ اگر کرسر کے ذریعہ اشارہ کیا گیا عنصر تقسیم کار کے ذریعہ اشارہ کردہ عنصر سے چھوٹا ہے، تو ہم اس عنصر کو بفر صف میں رکھتے ہیں اور کرسر کو منتقل کرتے ہیں۔ بصورت دیگر، ہم الگ کرنے والے کی طرف اشارہ کردہ عنصر کو بفر اری میں رکھتے ہیں اور الگ کرنے والے کو منتقل کرتے ہیں۔ جیسے ہی الگ کرنے والا ترتیب شدہ علاقے کی حدود سے باہر جاتا ہے یا ہم پوری صف کو بھرتے ہیں، مخصوص رینج کو ترتیب دیا جاتا ہے۔ متعلقہ مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 8

گنتی کی ترتیب اور ریڈکس ترتیب

ایک اور دلچسپ چھانٹنے والا الگورتھم کاؤٹنگ سورٹ ہے۔ اس معاملے میں الگورتھمک پیچیدگی O(n+k) ہوگی، جہاں n عناصر کی تعداد ہے، اور k عنصر کی زیادہ سے زیادہ قدر ہے۔ الگورتھم کے ساتھ ایک مسئلہ ہے: ہمیں صف میں کم سے کم اور زیادہ سے زیادہ قدروں کو جاننے کی ضرورت ہے۔ گنتی کی ترتیب کے نفاذ کی ایک مثال یہ ہے:
public static int[] countingSort(int[] theArray, int maxValue) {
        // Array with "counters" ranging from 0 to the maximum value
        int numCounts[] = new int[maxValue + 1];
        // In the corresponding cell (index = value) we increase the counter
        for (int num : theArray) {
            numCounts[num]++;
        }
        // Prepare array for sorted result
        int[] sortedArray = new int[theArray.length];
        int currentSortedIndex = 0;
        // go through the array with "counters"
        for (int n = 0; n < numCounts.length; n++) {
            int count = numCounts[n];
            // go by the number of values
            for (int k = 0; k < count; k++) {
                sortedArray[currentSortedIndex] = n;
                currentSortedIndex++;
            }
        }
        return sortedArray;
    }
جیسا کہ ہم سمجھتے ہیں، یہ بہت تکلیف دہ ہوتا ہے جب ہمیں کم از کم اور زیادہ سے زیادہ اقدار کو پہلے سے جاننا ہوتا ہے۔ اور پھر ایک اور الگورتھم ہے - Radix Sort. میں یہاں الگورتھم کو صرف بصری طور پر پیش کروں گا۔ عمل درآمد کے لیے مواد دیکھیں:
نظریہ اور عمل میں الگورتھم کی چھانٹی - 9
مواد:
نظریہ اور عمل میں الگورتھم کو ترتیب دینا - 10

جاوا فوری ترتیب

ٹھیک ہے، میٹھی کے لئے - سب سے زیادہ مشہور الگورتھم میں سے ایک: فوری ترتیب. اس میں الگورتھمک پیچیدگی ہے، یعنی ہمارے پاس O(n log n) ہے۔ اس قسم کو Hoare sort بھی کہا جاتا ہے۔ دلچسپ بات یہ ہے کہ الگورتھم کی ایجاد Hoare نے سوویت یونین میں اپنے قیام کے دوران کی تھی، جہاں اس نے ماسکو یونیورسٹی میں کمپیوٹر ٹرانسلیشن کی تعلیم حاصل کی تھی اور ایک روسی-انگریزی فقرے کی کتاب تیار کر رہے تھے۔ یہ الگورتھم جاوا میں Arrays.sort میں زیادہ پیچیدہ نفاذ میں بھی استعمال ہوتا ہے۔ Collections.sort کے بارے میں کیا خیال ہے؟ میرا مشورہ ہے کہ آپ خود دیکھیں کہ انہیں کس طرح "ہڈ کے نیچے" ترتیب دیا گیا ہے۔ تو، کوڈ:
public static void quickSort(int[] source, int leftBorder, int rightBorder) {
        int leftMarker = leftBorder;
        int rightMarker = rightBorder;
        int pivot = source[(leftMarker + rightMarker) / 2];
        do {
            // Move the left marker from left to right while element is less than pivot
            while (source[leftMarker] < pivot) {
                leftMarker++;
            }
            // Move the right marker until element is greater than pivot
            while (source[rightMarker] > pivot) {
                rightMarker--;
            }
            // Check if you don't need to swap elements pointed to by markers
            if (leftMarker <= rightMarker) {
                // The left marker will only be less than the right marker if we have to swap
                if (leftMarker < rightMarker) {
                    int tmp = source[leftMarker];
                    source[leftMarker] = source[rightMarker];
                    source[rightMarker] = tmp;
                }
                // Move markers to get new borders
                leftMarker++;
                rightMarker--;
            }
        } while (leftMarker <= rightMarker);

        // Execute recursively for parts
        if (leftMarker < rightBorder) {
            quickSort(source, leftMarker, rightBorder);
        }
        if (leftBorder < rightMarker) {
            quickSort(source, leftBorder, rightMarker);
        }
}
یہاں سب کچھ بہت خوفناک ہے، لہذا ہم اس کا پتہ لگائیں گے۔ ان پٹ اری int[]سورس کے لیے، ہم نے دو مارکر سیٹ کیے ہیں، بائیں (L) اور دائیں (R)۔ جب پہلی بار بلایا جاتا ہے، تو وہ صف کے آغاز اور اختتام سے ملتے ہیں۔ اگلا، معاون عنصر کا تعین کیا جاتا ہے، عرف pivot۔ اس کے بعد، ہمارا کام یہ ہے کہ اقدار کو بائیں طرف، اور بڑی کو دائیں طرف منتقل pivotکریں pivot۔ ایسا کرنے کے لیے، پہلے پوائنٹر کو اس وقت تک منتقل کریں Lجب تک کہ ہمیں اس سے بڑی قدر نہ مل جائے pivot۔ اگر اس سے چھوٹی قدر نہیں ملتی ہے، تو L совпадёт с pivot. Потом двигаем указатель R пока не найдём меньшее, чем pivot meaning. Если меньшее meaning не нашли, то R совпадёт с pivot. Далее, если указатель L находится до указателя R or совпадает с ним, то пытаемся выполнить обмен элементов, если элемент L меньше, чем R. Далее L сдвигаем вправо на 1 позицию, R сдвигаем влево на одну позицию. Когда левый маркер L окажется за правым маркером R это будет означать, что обмен закончен, слева от pivot меньшие значения, справа от pivot — большие значения. После этого рекурсивно вызываем такую же сортировку для участков массива от начала сортируемого участка до правого маркера и от левого маркера до конца сортируемого участка. Почему от начала до правого? Потому что в конце итерации так и получится, что правый маркер сдвинется настолько, что станет границей части слева. Этот алгоритм более сложный, чем простая sorting, поэтому его лучше зарисовать. Возьмём белый лист бумаги, запишем: 4 2 6 7 3 , а Pivot по центру, т.е. число 6. Обведём его в круг. Под 4 напишем L, под 3 напишем R. 4 меньше чем 6, 2 меньше чем 6. Total, L переместился на положение pivot, т.к. по условию L не может уйти дальше, чем pivot. Напишем снова 4 2 6 7 3 , обведём 6 вкруг ( pivot) и поставим под ним L. Теперь двигаем указатель R. 3 меньше чем 6, поэтому ставим маркер R на цифру 3. Так How 3 меньше, чем pivot 6 выполняем swap, т.е. обмен. Запишем результат: 4 2 3 7 6 , обводим 6 вкруг, т.к. он по прежнему pivot. Указатель L на цифре 3, указатель R на цифре 6. Мы помним, что двигаем указатели до тех пор, пока L не зайдём за R. L двигаем на следующую цифру. Тут хочется разобрать два варианта: если бы предпоследняя цифра была 7 и если бы она была не 7, а 1. Предпоследня цифра 1: Сдвинули указатель L на цифру 1, т.к. мы можем двигать L до тех пор, пока указатель L указывает на цифру, меньшую чем pivot. А вот R мы не можем сдвинуть с 6, т.к. R не мы можем двигать только если указатель R указывает на цифру, которая больше чем pivot. swap не делаем, т.к. 1 меньше 6. Записываем положение: 4 2 3 1 6, обводим pivot 6. L сдвигается на pivot и больше не двигается. R тоже не двигается. Обмен не производим. Сдвигаем L и R на одну позицию и подписываем цифру 1 маркером R, а L получается вне числа. Т.к. L вне числа — ничего не делаем, а вот часть 4 2 3 1 выписываем снова, т.к. это наша левая часть, меньшая, чем pivot 6. Выделяем новый pivot и начинаем всё снова ) Предпоследняя цифра 7: Сдвинули указать L на цифру 7, правый указатель не можем двигать, т.к. он уже указывает на pivot. т.к. 7 больше, чем pivot, то делаем swap. Запишем результат: 4 2 3 6 7, обводим 6 кружком, т.к. он pivot. Указатель L теперь сдвигается на цифру 7, а указатель R сдвигается на цифру 3. Часть от L до конца нет смысла сортировать, т.к. там всего 1 элемент, а вот часть от 4 до указателя R отправляем на сортировку. Выбираем pivot и начинаем всё снова ) Может на первый взгляд показаться, что если расставить много одинаковых с pivot значений, это сломает алгоритм, но это не так. Можно напридумывать каверзных вариантов и на бумажке убедиться, что всё правильно и подивиться, How такие простые действия предоставляют такой надёжный механизм. Единственный минус — такая sorting не является стабильной. Т.к. при выполнении обмена одинаковые элементы могут поменять свой порядок, если один из них встретился до pivot до того, How другой элемент попал в часть до pivot при помощи обмена. Материал:

Итог

Выше мы рассмотрели "джентельменский" набор алгоритмов сортировки, реализованных на Java. Алгоритмы вообще штука полезная, How с прикладной точки зрения, так и с точки зрения развития мышления. Некоторые из них попроще, некоторые посложнее. По Howим-то умные люди защищали различные работы на степени, а по другим писали толстые-толстые книги. Надеюсь, приложенный к статье материал позволит вам узнать ещё больше, так How это обзорная статья, которая и так получилась увесистой. И цель её — дать небольшое вступление. Про введение в алгоритмы можно так же прочитать ознакомиться с книгой " Грокаем Алгоримы". Также мне нравится плэйлист от Jack Brown — AQA Decision 1 1.01 Tracing an Algorithm. Ради интереса можно посмотреть на визуализацию алгоритмов на sorting.at и visualgo.net. Ну и весь Youtube к вашим услугам.
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION