Aamir Yousafi Ответов: 2

Сортировка слиянием без сбоя массивов


Дорогие все,

Мне пришла в голову блестящая идея сделать код сортировки слиянием без рекурсивного создания массивов (очевидно, не связанных списков). Логика кажется правильной, и каждая переменная ведет себя так, как должна, за исключением одной, и я просто не могу понять, почему. Надеюсь, у кого-нибудь найдется время мне помочь.

Я напишу отдельную программу, которая выполняет сортировку слиянием в связанных списках, но здесь я хотел преодолеть главную слабость сортировки слиянием с точки зрения дополнительных накладных расходов, поэтому решил поэкспериментировать с этим.

Пожалуйста, смотрите код ниже:

/* includes and macros */
// required for input / output with minGW GCC
#include <stdio.h>
#define printf __mingw_printf

// required for the dynamic storage allocation and the random integer generator functions
#include <stdlib.h>

// required for the time function, which is required for rand() to work properly
#include <time.h>



/* type definitions  (structs go here) */



/* global declarations */
static unsigned short n = 0;



/* function prototypes */
void swapSort (int *, int *);
void mergeSort (int []);



/* main function */
int main ()
{
	/* some initial declarations & initializations */
	// ask the user for the amount of integers to sort
	printf("How many integers do you want sorted by Merge Sort? ");
	scanf("%hu", &n);

	// for rand()
	srand(time(NULL));

	// array input
	int arrayInput[n];


	/* array input */
	// input taken from the rand() function
	printf ("\n");
	for (register unsigned short i = 0; i <= n-1; i++)
		arrayInput[i] = rand();

	// printing the input so the user knows exactly what rand() produced
	printf ("\n");
	for (register unsigned short i = 0; i <= n-1; i++)
		printf ("[%d] ", arrayInput[i]);
	printf ("\n");


	/* sort the list by Merge Sort */
	mergeSort(arrayInput);


	/* print the sorted array */
	printf("\n");
	for (register unsigned short i = 0; i <= n-1; i++)
		printf("[%d] ", arrayInput[i]);
	printf("\n");


	/* exit main and the program */
	return 0;
}



/* function definitions */
/* simple swapping function */
void swapSort (int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}


/* the Merge Sort function, improving upon bubble sort */
void mergeSort (int mainArray[])
{
	// sort the subarrays formed by every two elements, then by every four elements, then by 8, etc.
	for (unsigned short sizeSubArr = 2; sizeSubArr <= n;)  // set the outer loop so that it sorts all the subarrays of a specific size; the subarray size will change per iteration
									      // of the loop so there may be a remainder subarray of a different size than sizeSubArr
	SubArrayMarkers:
	{
		unsigned short total_number_of_subarrays = n / sizeSubArr;
		unsigned short remSizeSubArr = n % sizeSubArr;
		unsigned short subArrLen = sizeSubArr;
		for (unsigned short mainIndex = 0, subArrNo = 1; subArrNo <= total_number_of_subarrays; mainIndex++)  // a loop that marks the beginning of each subarray as it goes through
																	                   // the main array and then the subarray is sorted by this loop's inner loops
																	                   // it also keeps track of the index of the main array
		{
			BubbleSort:
			for (unsigned short j = 0; j <= n; j = 0)  // this is where bubble sort starts, with the infinite outer loop to be broken if there are no swaps done within the bubble sort
									    // we set l to mainIndex so that if there are multiple iterations of bubble sort, it doesn't screw up mainIndex
			{
				unsigned short l = mainIndex;
				for (register unsigned short k = 1; k <= subArrLen-1; k++, l++)  // one bubble sort iteration through the current sub array of the outer loop
				{
					if (mainArray[l] > mainArray[l+1])
					{
						swapSort(&mainArray[l], &mainArray[l+1]);
						j++;
					}
				}
				if (j == 0)
				{
					mainIndex = l;  // once a subarray is sorted, we need to set mainindex to l's current value so that it can start on the next subarray the next time bubble sort is invoked
					break;
				}
			}
			subArrNo++;  // the incrementation is done here so that a final iteration can be done on the loop based on the following if statement
			if ((subArrNo > total_number_of_subarrays) && (remSizeSubArr >= 2))
			{
				subArrLen = remSizeSubArr;
				mainIndex++;
				goto BubbleSort;
			}
		}
		sizeSubArr *= 2;  // the incrementation is done here so that a final iteration can be done on the loop based on the following if statement
		if (sizeSubArr > n && remSizeSubArr != 0)
		{
			sizeSubArr = n;
			goto SubArrayMarkers;
		}
	}
}


Что я уже пробовал:

Я отлаживал, отлаживал и отлаживал. Я точно определил проблему с переменной l, но не могу понять, почему она раздувается до значения 100+ даже для массива целых чисел 10. В любом случае, он не должен выходить за пределы 10.

2 Ответов

Рейтинг:
0

Patrice T

Здесь ошибка :

int arrayInput[n];

Это нормально до тех пор, пока n известно во время компиляции. В вашем случае вам нужно прибегнуть к указателю и динамическому выделению памяти во время выполнения.
Функция библиотеки C-malloc()[^]

Ошибка снова:
void mergeSort (int mainArray[])

вы не можете передать массив в качестве параметра, параметр должен быть указателем на массив.


Вот хорошая лекция:
Язык программирования Си - Википедия, свободная энциклопедия[^]
https://hassanolity.files.wordpress.com/2013/11/the_c_programming_language_2.pdf[^]
http://www.ime.usp.br/~ПФ/Керниган-Ритчи/с-Программирование-электронные книги.формат PDF[^]

[Обновление]
- Сортировка пузырьков выполняется на месте, потому что для выполнения сортировки используется только свопинг.
- Быстрая сортировка и сортировка слиянием оба должны прибегать к копированию массива, потому что часть слияния не может быть выполнена на месте (или для слияния на месте требуется специальное Программирование).

С помощью связанного списка вы можете избежать копирования данных, потому что все делается путем изменения указателей, но это обходится дорого.


Aamir Yousafi

ppolymorphe, да, вы, вероятно, правы насчет динамического распределения памяти. Отныне я буду использовать его для всех своих массивов, независимо от того, являются ли они связанными списками.

Что касается массива / указателя, передаваемого функции, то мой опыт показывает, что если вы передаете указатель, вы должны передать его как таковой, а когда вы передаете массив, вы передаете его как таковой. Я помню, как был разочарован своим кодом алгоритма быстрой сортировки для рекурсивных вызовов, когда пытался передать указатели, которые работали бы с массивами, потому что он терпел крах. Наконец, когда я изменил все эти указатели на массивы, которые будут рекурсивно объявлены и рекурсивно переданы функции quicksort, я заставил ее работать. Я могу поделиться с вами своим кодом быстрой сортировки, чтобы вы знали, к чему я клоню.

Aamir Yousafi

Так что, на самом деле, если у вас есть способ исправить эту функцию quicksort так, чтобы ей не нужно было создавать новые массивы, чего я старался избежать, то я бы с удовольствием это сделал. Дайте мне знать, если вы хотите, чтобы я поделился этим кодом.

Рейтинг:
0

Aamir Yousafi

Ладно ... извините, все. Я нашел решение. Это было утверждение "Если", которое все испортило. Во всяком случае, вот обновленный код оператора if, который вызвал эту проблему:

if ((subArrNo > total_number_of_subarrays) && (remSizeSubArr >= 2))
{
    if (remSwaps != 0)
        break;
    subArrLen = remSizeSubArr;
    mainIndex++;
    remSwaps++;
    goto BubbleSort;
}