I'm trying to implement merge sort in C using arrays, here's my code:
#include <stdio.h>
#include <stdlib.h>
void merge(int s[], int low, int middle, int high)
{
int i,l=0,r=0;
int left[high/2], right[high/2];
for(i = low; i<=middle; i++) left[i-low] = s[i];
for(i = middle+1; i<=high; i++) right[i-middle-1] = s[i];
i = low;
while(l <= middle-low || r <= high - middle - 1)
{
if(left[l] <= right[r])
{
s[i++] = left[l];
l++;
}
else
{
s[i++] = right[r];
r++;
}
}
while(l <= middle-low)
{
s[i++] = left[l];
l++;
}
while(r <= high - middle - 1)
{
s[i++] = left[r];
r++;
}
}
void mergesort(int s[], int low, int high)
{
int i;
int middle;
if(low < high){
middle = (low + high)/2;
mergesort(s, low, middle);
mergesort(s, middle+1, high);
merge(s, low, middle, high);
}
}
int main()
{
int nums[] = {5, 345, 1, 120, 40, 3450};
int size = (sizeof(nums))/(sizeof(int));
int i;
for(i = 0; i < size; i++)
printf("%d ", nums[i]);
printf("\n");
mergesort(nums, 0, size);
for(i = 0; i < size; i++)
printf("%d ", nums[i]);
printf("\n");
return 0;
}
That outputs:
5 345 1 120 40 3450
0 1 4 5 40 120
Which is kind of close. Could someone point out my mistakes? Thank you.
You access the array out of bounds at several places. Your code uses C-style ranges, which have an inclusive lower bound L and an exclusive upper bound H. Exclusive means that the upper bound H is not a valid index in the (sub-)array. A typical loop over the range look like this:
for (i = L; i < U; i++) ...
or
i = L;
while (i < U) ...
A greater-than-or-equal operator <= in such loops should make you wary, as should suprious additions or subtraction of 1. They might be correct in some cases, but they are usually consequences of inconsitent array indexing.
Let's revise your code with the C-style ranges in mind:
int left[high/2], right[high/2];
The array sizes are wrong. The left array has middle - low elements and the right array has high - middle elements. If the array size high - low is odd, you have one more element in right than in left.
for(i = low; i<=middle; i++) left[i-low] = s[i];
You mistakenly put the middle element in the left array. It is the first element of the right array.
for(i = middle+1; i<=high; i++) right[i-middle-1] = s[i];
Same here, plus you access s[high] which is one beyond the array.
i = low;
while(l <= middle-low || r <= high - middle - 1)
The conditions should have < and no -1. More importantly, the conditions should both be true, otherwise you access the subarrays out of bounds; hence the operator should be ยด&&`.
if(left[l] <= right[r])
The <= is okay, though, for once.
while(l <= middle-low)
{
s[i++] = left[l];
l++;
}
while(r <= high - middle - 1)
{
s[i++] = left[r];
r++;
}
Here, it should be < again. Also note that you access left with the index r, which is probably just a typo owed to copy and paste.
if(low < high){
middle = (low + high)/2;
mergesort(s, low, middle);
mergesort(s, middle+1, high);
merge(s, low, middle, high);
}
Here, the second call to megesort should be to middle, not to middle + 1. Because the upper bound is exclusive and the lower is not, adjacent arrays share the same bounds.
Here's a sort that works:
void merge(int s[], int low, int middle, int high)
{
int i, l = 0, r = 0;
int left[middle - low];
int right[high - middle];
for (i = low; i < middle; i++) left[i - low] = s[i];
for (i = middle; i < high; i++) right[i - middle] = s[i];
i = low;
while (low + l < middle && middle + r < high) {
if (left[l] < right[r]) {
s[i++] = left[l];
l++;
} else {
s[i++] = right[r];
r++;
}
}
while (low + l < middle) {
s[i++] = left[l];
l++;
}
while (middle + r < high) {
s[i++] = right[r];
r++;
}
}
void mergesort(int s[], int low, int high)
{
int middle;
if (low + 1 < high) {
middle = (low + high) / 2;
mergesort(s, low, middle);
mergesort(s, middle, high);
merge(s, low, middle, high);
}
}
The code can still be improved. The different indices for the left and right subarrays make it difficult to maintain and test the code. If you have already learned about pointer arithmetic, you can do without the low bound entirely by passing array + low and the size as new array base, as EOF has suggested in a comment.
M Oehm provided an explanation and a fixed example of the original code in his answer.
Here is an alternate version that does a one time allocation of the temporary array and uses a pair of co-recursive functions to avoid copying of data. I'm not sure why top down merge sort is used so often, bottom up merge sort is non-recursive, a little bit faster, and simpler to understand.
On my system, Intel 2600K 3.4ghz, this example can sort 20 million 32 bit integers in about 2 seconds. (A bottom up merge sort would take about 1.9 seconds).
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee);
void TopDownMergeSort(int a[], size_t n)
{
int *b;
if(n < 2) // if size < 2 return
return;
b = malloc(n * sizeof(int)); // one time allocation
TopDownSplitMergeAtoA(a, b, 0, n);
free(b);
return;
}
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
{
size_t rr;
if((ee - ll) == 1) // if size == 1 return
return;
rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoB(a, b, ll, rr);
TopDownSplitMergeAtoB(a, b, rr, ee);
MergeRuns(b, a, ll, rr, ee); // merge b to a
}
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
{
size_t rr;
if((ee - ll) == 1){ // if size == 1 copy a to b
b[ll] = a[ll];
return;
}
rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoA(a, b, ll, rr);
TopDownSplitMergeAtoA(a, b, rr, ee);
MergeRuns(a, b, ll, rr, ee); // merge a to b
}
void MergeRuns(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}
Related
#include <stdio.h>
void msort(int *a, int n);
void msort_recursion(
int a[], int left,
int right);
void merge_arrays(int a[], int left, int middle,
int right); // merges the sorted portions of the array
int main() {
int a[] = {5, 2, 4, 1, 3};
int n = 5;
msort(a, n);
printf("[");
for (int i = 0; i < n; i++)
if (i == n - 1) {
printf("%d", a[i]);
} else {
printf("%d, ", a[i]);
}
printf("]\n");
return 0;
}
void msort(int *a, int n) { msort_recursion(a, 0, n - 1); }
void msort_recursion(int a[], int left, int right) {
if (left < right) {
int middle = left + (right - 1) / 2;
msort_recursion(a, left, middle);
msort_recursion(a, middle + 1,
right);
merge_arrays(a, left, middle,
right);
}
}
void merge_arrays(
int a[], int left, int middle,
int right) {
int left_size = middle - left + 1;
int right_size = right - middle;
int templ[left_size];
int tempr[right_size];
int i, j, k;
for (int i = 0; i < left_size; i++)
templ[i] = a[left + i];
for (int i = 0; i < right_size; i++)
tempr[i] = a[middle + 1 + i];
for (i = 0, j = 0, k = left; k <= right; k++) {
if ((i < left_size) && (j >= right_size || templ[i] <= tempr[j])) {
a[k] = templ[i];
i++;
} else {
a[k] = tempr[j];
j++;
}
}
}
Merge sort is implemented in Code, but when run, I receive the error code "signal: segmentation fault (core dumped)" which to my understanding, means that it has reached past the end of an array but I do not understand how this is... Merge sort is implemented in Code, but when run, I receive the error code "signal: segmentation fault (core dumped)" which to my understanding, means that it has reached past the end of an array but I do not understand how this is...
The reason is you called msort_recursion recursively to many times this happened because the middle is computed wrong and should be int middle = left + (right - left) / 2; notice it's the difference in position split in half.
make sure to read geeksforgeeks.org/merge-sort more carefully next time
void msort_recursion(int a[], int left, int right) {
if (left < right) {
int middle = left + (right - 1) / 2;
/* Here should be ^^^^^^^^^ right - left */
msort_recursion(a, left, middle);
msort_recursion(a, middle + 1,right);
merge_arrays(a, left, middle,right);
}
}
for msort_recursion, I was doing int middle = left + (right - 1) / 2 instead of int middle = left + (right - left) / 2
#include <stdio.h>
void msort(int *a, int n); // merge sort array a with n elements in place in C
void msort_recursion(int a[], int left, int right); // recursion where the array is continuously divided in half
// until there is only one element left
void merge_arrays(int a[], int left, int middle, int right); // merges the sorted portions of the array
int main() {
int a[] = {5, 2, 4, 1, 3};
int n = 5;
msort(a, n);
// print sorted array
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
void msort(int *a, int n) {
msort_recursion(a, 0, n - 1);
}
void msort_recursion(int a[], int left, int right) {
// as long as the left is less than the right, we will continuously divide the
// array
if (left < right) {
int middle = left + (right - left) / 2; // find the middle of the array
msort_recursion(a, left, middle); // recursion on the left side of the array
msort_recursion(a, middle + 1, right); // recursion on the right side of the array
merge_arrays(a, left, middle, right); // merge the sorted sections of the array
}
}
void merge_arrays(int a[], int left, int middle, int right) { // left is the index for the start of the array, middle is the
// middle index, right is the index of the last element in the
// right section of the array
int left_size = middle - left + 1; // size of left side of array
int right_size = right - middle; // size of right side of the array
// create 2 tepm sub arrarys and copy the portions into the sub arrays
int templ[left_size];
int tempr[right_size];
int i, j, k; // i is keeping track of left array, j is keeping track of right
// array, k is keeping track of original array a
for (int i = 0; i < left_size; i++)
// copy left side into left temp array
templ[i] = a[left + i];
for (int i = 0; i < right_size; i++)
// copy right side into right temp array
tempr[i] = a[middle + 1 + i];
// pick from the sorted left and right arrays to replace into the original
// array
for (i = 0, j = 0, k = left; k <= right; k++) {
if ((i < left_size) && (j >= right_size || templ[i] <= tempr[j])) {
// if the element in the left array is smaller than the element in the
// right array then replace it in array a as long as we don't reach the end
// of either the left or right arrays
a[k] = templ[i];
i++;
// otherwise, put the right element into the array a
} else {
a[k] = tempr[j];
j++;
}
}
}
I wrote a merge sort program but I got wrong results.
I've seen other programs like this, but they don't help me solve my problem. I think the problem is in the merge function.
#include <stdio.h>
#include "stdafx.h"
#define Size 5
//this is the array
int arr[Size] = { 5, 4, 3, 2, 1 };
int sr[10];
void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);
int main(void) {
mergesort(arr, 0, 4, 5);
for (int i = 0; i < Size; i++) {
printf_s("%i", sr[i]);
}
printf_s("\n");
return 0;
}
void mergesort(int a[], int start, int end, int size) {
if (size < 2)
return;
int s = size / 2;
mergesort(a, start, (start + end) / 2, s);
mergesort(a, (start + end) / 2, end, s);
merge( a, start, end, s);
}
void merge(int a[], int start, int end, int size) {
int left = start;
int right = ((start + end) / 2) + 1;
for (int i = 0; i < size; i++) {
if (left < (start + end)/2) {
if (right >= end) {
sr[i] = arr[left];
left++;
} else
if (arr[left] < arr[right]) {
sr[i] = arr[left];
left++;
} else {
sr[i] = arr[right];
right++;
}
} else {
sr[i] = arr[right];
right++;
}
}
}
(1)
printf_s("%i",sr[i]); should be printf_s("%i ", arr[i]);
(2)
mergesort(a, start, (start + end) / 2, s);//E.g index:{0,1,2,3,4}, start:0, (start + end) / 2 : 2, s: 2, but 0(start),1,2(new end), this length is 3, not 2
mergesort(a, (start + end) / 2, end, s);//Duplicate start position and length should be size - s. E.g size:5, s:2, rest size is 3, not 2.
merge( a, start, end, s);//s should be size
should be like
mergesort(a, start, start + s - 1, s);
mergesort(a, start + s, end, size - s);
merge(a, start, end, size);
(3)
Change according to (2)
Change int right = ((start + end) / 2) +1; to int right = start + size / 2;.
(4)
Add int sr[size]; //Avoid using global variables. It is better to use malloc. E.g int *sr = malloc(size*sizeof(int));...free(sr);
(5)
if (left < (start+end)/2)
{
if (right >= end)
should be
if (left < start + size / 2)
{
if (right > end){//Should be >, not >=
(6) Write back to arr form sr is necessary
Whole code:
#include <stdio.h>
#include <stdlib.h>
void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);
int main(void){
int arr[] = {5,4,3,2,1};
int size = sizeof(arr)/sizeof(*arr);
mergesort(arr, 0, size - 1, size);
for (int i = 0; i < size; i++){
printf_s("%i ", arr[i]);
}
printf_s("\n");
return 0;
}
void mergesort(int a[], int start, int end, int size){
if (size < 2)
return;
int s = size / 2;
mergesort(a, start, start + s - 1, s);
mergesort(a, start + s, end, size - s);
merge(a, start, end, size);
}
void merge(int a[], int start, int end, int size){
int left = start;
int right = start + size / 2;
int right_start = right;
int *sr = (int*)malloc(size*sizeof(*sr));//Cast(int*) is not necessary in C.
for (int i = 0; i < size; i++){
if (left < right_start){
if (right > end){
sr[i] = a[left++];
} else if (a[left] < a[right]) {
sr[i] = a[left++];
} else {
sr[i] = a[right++];
}
} else {
sr[i] = a[right++];
}
}
for(int i = 0; i < size; ++i)//write back.
a[start + i] = sr[i];
free(sr);
}
Your code is invalid for multiple reasons:
mergesort splits the range into 2 halves of size size / 2, which is incorrect if size is not even.
the arguments to mergesort are incorrect, only the pointer and the size are needed.
the merge function gets values from the global array arr instead of the argument array and stores values into the global temporary array sr, but does not copy it back into the a array.
Here is a corrected and simplified version:
#include <stdio.h>
void mergesort(int a[], int size);
int main(void) {
int arr[] = { 5, 4, 3, 2, 1 };
int size = sizeof(arr) / sizeof(arr[0]);
mergesort(arr, size);
for (int i = 0; i < size; i++) {
printf_s("%i ", arr[i]);
}
printf_s("\n");
return 0;
}
void merge(int a[], int mid, int size) {
int sr[mid]; // temporary array for the left part
if (a[mid - 1] <= a[mid]) { // quick check for sorted case
return;
}
for (int i = 0; i < mid; i++) { // save left part
sr[i] = a[i];
}
// merge into array `a`.
for (int i = 0, left = 0, right = mid; left < mid; i++) {
if (right == size || sr[left] <= a[right]) {
a[i] = sr[left++];
} else {
a[i] = a[right++];
}
}
}
void mergesort(int a[], int size) {
if (size >= 2) {
int mid = (size + 1) / 2; // make left part no smaller than right part
mergesort(a, mid);
mergesort(a + mid, size - mid);
merge(a, mid, size);
}
}
I have the following partition method and kthsmallest method (Variation of quicksort) which works for some cases but gives me the value 32767 for a few cases.
void swap(int* a, int* b){
int temp = *b;
*b = *a;
*a = temp;
}
int partition(int* arr, int l, int r){
int pivot = arr[r];
int i = l, j=0;
for(j=l; j<=r-1; j++){
if(arr[j] <= pivot){
swap(&arr[i], &arr[j]);
i++;
}
}
swap(&arr[i], &arr[j]);
return i;
}
And the kthsmallest function is as follows:-
int kthsmallest(int* arr, int low, int high, int k){
/* low = 0 and high = #elements - 1 */
/* k is in between 1 to high + 1 */
if (k>0 & k<=high-low+1) {
// pos is partitioning index, arr[p] is now at right place
int pos = partition(arr, low, high);
// Separately sort elements before / partition and after partition
if(pos-low == k-1){
return arr[pos];
}
//if position returned is greater than k, recurse left subarray
else if(pos-low > k-1){
return kthsmallest(arr, low, pos-1, k);
}
return kthsmallest(arr, pos+1, high, k-(pos+1));
}
}
However it works when I change the last call in kthsmallest function i.e.
Change: return kthsmallest(arr, pos+1, high, k-(pos+1));
To: return kthsmallest(arr, pos+1, high, k-(pos+1)+low);
I want to understand why I need to add low to k-(pos+1). Because in my view, when we have the subarray on the right in which the recursion enters, the kth smallest number in the large array boils down to k - last partition element -1 i.e. k-(pos+1).
You need low because when you recursively start with a new array, low will be the reference for pos. So the new k will be calculated from low to pos.
Maybe an example would be more clarifying.
Lets find the 9th smallest element of this array:
Now we do the partition, so we get:
From pos to the left we've got the smallest elements in the array, that's the 3 smallest elements. Now we'll work with the subarray starting from pos+1. And we need to get the 6th smallest element:
We do a partition over this subarray:
Remember that we are working over a subarray trying to find the 6th smallest element. In this case we separated the (pos - low + 1)th smallest elements in the subarray. So our new k will be:
We do a new partition:
Now we exceeded the 4th smallest element of the last subarray, so we trim the last part:
We do the partition again:
And we get:
So our number is 17.
Hope it helps.
PD: As David C. Rankin says in comments you probably should change & for &&.
It appears one of the problems you are having is trying to shoehorn a quickselect routine into a recursive function when there is no reason to make the function recursive to begin with. All you need to do is identify the partition the 'k' element resides in, there is no need to sort. All you need for your kthsmallest is:
/** select the ZERO BASED 'k' element from 'arr'.
* where 'low' and 'high' are the ZERO BASED low
* and high indexes for 'arr'.
*/
int kthsmallest (int *arr, int low, int high, int k)
{
for (;;) {
if (low == high)
return arr[low];
int pos = partition (arr, low, high);
if (k == pos)
return arr[k];
else if (k < pos)
high = pos - 1;
else
low = pos + 1;
}
}
Using your exact partition and swap functions, you can write a small example program to test k for every element in an array. (note: the element returned is based on a zero indexed k, e.g. the first smallest element is offset zero from the end of the array -- just like in the rest of C)
#include <stdio.h>
void swap (int *a, int *b);
int partition (int *arr, int l, int r);
/** select the ZERO BASED 'k' element from 'arr'.
* where 'low' and 'high' are the ZERO BASED low
* and high indexes for 'arr'.
*/
int kthsmallest (int *arr, int low, int high, int k)
{
for (;;) {
if (low == high)
return arr[low];
int pos = partition (arr, low, high);
if (k == pos)
return arr[k];
else if (k < pos)
high = pos - 1;
else
low = pos + 1;
}
}
int main (void) {
int a[] = { 51, 86, 34, 79, 92, 68, 14, 47, 22, 6 },
nelem = sizeof a / sizeof *a;
for (int i = 0; i < nelem; i++)
printf (" nth (%2d) element is : %d\n", i,
kthsmallest (a, 0, nelem - 1, i));
return 0;
}
void swap (int *a, int *b)
{
int temp = *b;
*b = *a;
*a = temp;
}
int partition (int *arr, int l, int r)
{
int pivot = arr[r];
int i = l, j = 0;
for (j = l; j <= r - 1; j++) {
if (arr[j] <= pivot) {
swap (&arr[i], &arr[j]);
i++;
}
}
swap (&arr[i], &arr[j]);
return i;
}
Example Use/Output
$ ./bin/kthsmall
nth ( 0) element is : 6
nth ( 1) element is : 14
nth ( 2) element is : 22
nth ( 3) element is : 34
nth ( 4) element is : 47
nth ( 5) element is : 51
nth ( 6) element is : 68
nth ( 7) element is : 79
nth ( 8) element is : 86
nth ( 9) element is : 92
About the question how to convert a string to palindrome with minimum number of removals of characters of the string? . I write the program to test the answer accepted. But recursion takes too much time. How can this problem be solved or improved?Below is the answer accepted:
Let dp[i, j] = minimum number of removals needed to convert the substring [i, j] to a palindrome. We have:
dp[i, i] = 0 for all i (every single character is a palindrome)
To
find dp[i, j], let's consider a random string. We have two
possibilities:
The first and last characters are equal: a[i] == a[j]. In this case,
we can reduce the problem to finding the minimum number of characters
that need to be deleted in order to make the substring [i+1, j-1] a
palindrome.
The first and last characters are not equal: a[i] != a[j].
In this case, we need to remove one of them. We'll remove that which
leads us to a better solution.
/* remvoe the least characters to make a string be palindrome */
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
int func(char *p, int low, int high);
int min(int m, int n); // get the minimal value
int main(void)
{
char str[MAXLINE];
int ret;
while (scanf("%s", str) != EOF) { // input in a loop
ret = func(str, 0, strlen(str) - 1); // call func
printf("%d\n", ret);
}
return 0;
}
/* find the minimal number of characters in a string,
* which are needed removed to make the string be palindrome
*/
int func(char *p, int low, int high)
{
int n;
int l;
int r;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
}
else {
l = func(p, low + 1, high);
r = func(p, low, high - 1);
n = min(l, r) + 1;
}
return n;
}
/* return the minimal variable */
int min(int m, int n)
{
return (m < n ? m : n);
}
A key improvement is to recognize that when only one side of the string is eliminated, the other side must have a match (with a character on the other side, even if it is itself), else why not eliminate both sides?
When a character from one side is removed, seek from that side toward the other for a match of the other side's character. (A match is always be found.) This eliminates many unnecessary recursion paths.
A secondary improvement "short-circuits" as below. No need to test other combinations as they cannot improve the result.
if (left == 1) return 1;
int func(const char *p, int low, int high) {
int n;
int left;
int right;
count++;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
} else {
#if 0
left = func(p, low + 1, high);
// if (left == 0) return 1;
right = func(p, low, high - 1);
n = min(left, right) + 1;
#else
int delta;
// remove low, keep high as part of palindrome
delta = 1;
while (p[low + delta] != p[high])
delta++;
left = func(p, low + delta, high) + delta;
if (left == 1) return 1;
// remove high, keep low as part of palindrome
delta = 1;
while (p[low] != p[high - delta])
delta++;
right = func(p, low, high - delta) + delta;
if (right <= 2) return right;
n = min(left, right);
// remove first and last
//int both = func(p, low + 1, high-1) + 1 + (high > (low + 1));
int both = func(p, low + 1, high - 1) + 2;
n = min(n, both);
#endif
}
return n;
}
Mouse over for final result of OP's test string (Hidden in case OP does not want to see it right away.)
count = 13090 ret = 45 str = 'jfdasflkjddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj'
A minor improvement uses const. Some compliers will generate more efficient code knowing the buffer is unchanging. Better compilers may detect this anyways.
// int func(char *p, int low, int high)
int func(const char *p, int low, int high)
Some test driver code
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
unsigned long long count = 0;
int func(const char *p, int low, int high);
int min(int m, int n); // get the minimal value
void testfunc(const char *str) {
count = 0;
int ret = func(str, 0, (int) strlen(str) - 1); // call func
printf(" count = %llu", count);
printf(" ret = %d", ret);
printf(" str = '%s' ++", str);
puts("");
fflush(stdout);
}
int main(void) {
char str[MAXLINE];
int ret;
char t[] =
"jfdasflkjdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"ddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
for (size_t i = 0; t[i]; i++) {
strncpy(str, t, i);
str[i] = 0;
testfunc(str);
}
return 0;
}
int min(int m, int n) {
return (m < n ? m : n);
}
int func(const char *p, int low, int high) {
...
you shouldn't call it recursively, because that leads to multiple execution of the same check (some range will be checked many times, when in reality only one check is required). Instead u should use a "dynamic programming" method, build from bottom to top. What that means is u need to create a two-dimensional array, dp[i][j], i<j, which stores the length of a maximum palindrome in range i to j. So if j=i+k first u proceed to build for k=0, then for k=1 and so on.
I have a problem in my pretty easy algorithm - quicksort in C.
It is very efficient (about 0.1s with randomize and checking if the list is sorted) but when i want to sort more than 500k elements it crashes.
Unfortunatelly i need to sort more of them because i need to write some kind of summary at the end :(
Here is my code, maybe someone will see a stupid mistake.
Thanks in advance!
int quick (int a[],int begin,int end)
{
int i = begin, j = end, w, q, pivot, k;
q=begin+end;
q=q/2;
pivot=a[q];
while (1)
{
while (a[j] > pivot && j>=0)
j=j-1;
while (a[i] < pivot && i<j)
i=i+1;
if (i < j)
{
k = a[i];
a[i] = a[j];
a[j] = k;
i++;
j--;
}
else
return j;
}
}
void quicks (int a[], int begin, int end)
{
int x;
if (end>begin)
{
x=quick(a,begin,end);
quicks(a,begin,x);
quicks(a,x+1,end);
}
}
It seems that i just need to use malloc and it is working fine. Thanks a lot for Your help!
You are suffering from RAM exhaustion/rollover: As you use an array of int, each of them requires 4 bytes. Your memory mapping is handled using size_t-type indexes. If you are compiling in 32-bit mode (which is probably your case), the maximum number it can get at is 2147483648 (2^31). With 4 bytes per int, you can only handle 536870912 elements (2^31 / 4).
As the system requires some RAM for other purposes (e.g. globals), you can only use a bit more than 500K entries.
Solution: Use a 64-bit compiler and you should be fine.
BR
Here is another and simpler implementation.
void quickSort(int a[], int begin, int end)
{
int left = begin - 1, right = end + 1, tmp;
const int pivot = a[(begin+end)/2];
if (begin >= end)
return;
while(1)
{
do right--; while(a[right] > pivot);
do left++; while(a[left] < pivot);
if(left < right)
{
tmp = a[left];
a[left] = a[right];
a[right] = tmp;
}
else
break;
}
quickSort(a, begin, right);
quickSort(a, right+1, end);
}
You call it like this
int main(void)
{
int tab[5] = {5, 3, 4, 1, 2};
int i;
quickSort(tab, 0, 4); // 4 is index of lest element of tab
for(i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
return 0;
}