Can anyone help me with this code because when it's executed it doesn't sort correctly the array. I can't figure out what's wrong.
I use this struct and get the data from a file
typedef struct record {
int id_field;
char string_field[20];
int int_field;
double double_field;
} record;
typedef int (*CompareFunction)(void *, void *);
and this is the quick sort:
void swap(void **a, void **b) {
void *tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void quick_sort(void **array, int left, int right, CompareFunction compare) {
int index;
if (left < right) {
index = partition(array, left, right, compare);
quick_sort(array, left, index - 1, compare);
quick_sort(array, index + 1, right, compare);
}
}
int partition(void **array, int left, int right, CompareFunction compare) {
int pivot = left + (right - left) / 2;
int i = left;
int j = right;
while (i < j) {
if (compare(array[i], array[pivot]) < 0) {
i++;
} else {
if (compare(array[j], array[pivot]) > 0) {
j--;
} else {
swap(&array[i], &array[j]);
i++;
j--;
}
}
}
swap(&array[pivot], &array[j]);
return j;
}
This is the compare function for int:
int compare_int_struct(void *ptr1, void *ptr2) {
int i1 = (*((record *) ptr1)).int_field;
int i2 = (*((record *) ptr2)).int_field;
if (i1 < i2) {
return -1;
}
if (i1 == i2) {
return 0;
}
return 1;
}
for example:
given array sorted array
233460 | 233460
4741192 | 1014671
1014671 | 1188961
496325 | 3119429
4476757 | 496325
3754104 | 2146160
4271997 | 2163766
4896376 | 2369159
2735414 | 3754104
2163766 | 2735414
2369159 | 4271997
1188961 | 4476757
3843159 | 4741192
2146160 | 3843159
It seems it orders in small blocks
The problems are in your partition routine.
You are selecting a pivot index, you then proceed to partition the (sub)array by comparing values indirectly via this index, and the value identified by l or r, respectively.
However, as you go, swapping values, sooner or later your selected pivot value will change its position in the array and you're now comparing to whatever happens to wind up at the pivot index.
Instead, you should save off the pivot value and compare to that. This has the added benefit that it saves array indexing within the inner loops:
int partition(void **array, int left, int right, CompareFunction compare) {
int pivot = left + (right - left) / 2;
int pivotValue = array[pivot]; // ********
int i = left;
int j = right;
while (i < j) {
if (compare(array[i], pivotValue) < 0) { // ********
i++;
} else {
if (compare(array[j], pivotValue) > 0) { // ********
j--;
} else {
swap(&array[i], &array[j]);
i++;
j--;
}
}
}
swap(&array[pivot], &array[j]);
return j;
}
And then there's that final swap. This is something you would use if you had chosen, up front, to move the selected pivot to the beginning or the end of the array and exclude that index from the remaining partitioning process. Several variants do this, but here that swap is just messing things up and should be removed.
Thank you all for your answers. I modified the the partition and now it works:
int pivot = left;
int i = left + 1;
int j = right;
while (i <= j) {
if (compare(array[i], array[pivot]) < 0) {
i++;
} else {
if (compare(array[j], array[pivot]) > 0) {
j--;
} else {
swap(&array[i], &array[j]);
i++;
j--;
}
}
}
swap(&array[pivot], &array[j]);
return j;
Related
I have to implement a priority queue using binary heap in C for the university assignment. Program should get the n values from input, when value is 0, it should print the ID number(so, if task that was added as 5th element has the highest priority 7, print "5") and remove the highest-priority task from queue, and when value>0 it should add new node. To implement ID's and priority, I used arrays of structs.
The task would be quite simple, if not the fact that it should also print lower ID's if the priority of elements are the same...
I've done my research, but the only advice that I've managed to found is to modify the fragments of typical heap functions (insertkey, heapify) to also look for elements' ID. I've tried to do this, but I have no idea what went wrong - elements are still not sorted in the way I want them to be. I would be grateful for any piece of advice and tips!
Code:
#include <stdio.h>
#define SIZE 99999
int heapsize = 0;
int count = 0;
struct pqueue
{
int priority;
int id;
};
struct pqueue A[SIZE];
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void initializearray()
{
for(int i=0; i<SIZE; i++)
{
A[i].priority = 0;
A[i].id = 0;
}
}
void printheap(); //prototype of debugging function
int left(int i)
{
return (i * 2) + 1;
}
int right(int i)
{
return (i * 2) + 2;
}
int parent(int i)
{
return ((i - 1) / 2);
}
void insertkey(int z)
{
heapsize++;
int i = heapsize - 1;
A[i].priority = z;
count++;
A[i].id = count;
while (i != 0 && A[parent(i)].priority < A[i].priority)
{
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
i = heapsize-1;
while(i != 0 && A[parent(i)].priority == A[i].priority && A[parent(i)].id > A[i].id )
{
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
// printheap();
}
void maxheapify(int i)
{
int l = left(i);
int r = right(i);
int largest;
if (l <= heapsize && A[l].priority >= A[i].priority)
{
largest = l;
if(A[l].priority == A[i].priority)
{
if(A[l].id < A[i].id)
{
largest = l;
}
else
{
largest = i;
}
}
}
else
{
largest = i;
}
if (r <= heapsize && A[r].priority >= A[largest].priority)
{
largest = r;
if(A[r].priority == A[largest].priority)
{
if(A[r].id < A[largest].id)
{
largest = r;
}
}
}
if (largest != i)
{
swap(&A[i].priority, &A[largest].priority);
swap(&A[i].id, &A[largest].id);
maxheapify(largest);
}
}
int extractmax()
{
int max = A[0].id;
A[0].priority = A[heapsize-1].priority;
A[0].id = A[heapsize-1].id;
heapsize--;
//printheap();
maxheapify(0);
return max;
}
void printheap() // debug function
{
for(int i = 0; i < heapsize; i++)
{
printf("prio %d id %d \n", A[i].priority, A[i].id);
}
}
int main()
{
int n;
int z;
initializearray();
scanf("%d", &n);
for(int i=0; i<n; i++)
{
scanf("%d", &z);
if(z != 0)
{
insertkey(z);
}
else
{
int local = extractmax();
if(local != 0 && heapsize+1 != 0)
{
printf("%d\n", local);
// printheap();
}
}
}
return 0;
}
Example input:
7
3 0 0 2 8 8 0
Output:
1
3
Example input (here comes the problem:)
10
1 1 1 1 2 0 0 0 0 0
Output:
5
3
2
4
1
Expected output:
5
1
2
3
4
Thank you for your time!
Instead of incorporating the logic directly into the heap implementation, write a comparison function that considers the id if the priorities are the same:
int pqless(const struct pqueue *a, const struct pqueue *b)
{
if (a->priority < b->priority) return 1;
if (a->priority > b->priority) return 0;
return (a->id > b->id);
}
This function returns true if a's priority is less than b's. If both priorities are equal, it returns true if a's id is smaller than b's.
Now update your heap code. Wherever you compare the priorities in the original code, now just call the function:
void insertkey(int z)
{
int i = heapsize++;
A[i].priority = z;
A[i].id = ++count;
while (i != 0 && pqless(&A[parent(i)], &A[i])) {
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
}
void maxheapify(int i)
{
int l = left(i);
int r = right(i);
int largest = i;
if (l <= heapsize && !pqless(&A[l], &A[i])) largest = l;
if (r <= heapsize && !pqless(&A[r], &A[largest]))largest = r;
if (largest != i) {
swap(&A[i].priority, &A[largest].priority);
swap(&A[i].id, &A[largest].id);
maxheapify(largest);
}
}
I am trying to write a recursive sort function with no loops at all.
void insertionSortRecursive(int arr[], int n)
{
if (n <= 1)
return;
insertionSortRecursive( arr, n-1 );
int last = arr[n-1];
int j = n-2;
while (j >= 0 && arr[j] > last)
{
arr[j+1] = arr[j];
j--;
}
arr[j+1] = last;
}
Is there a way to get rid of while loop and still make this function work?
Use the following code which comes in here (remove the while using another recursive function):
void insertInOrder( int element,int *a, int first, int last)
{
if (element >= a[last])
a[last+1] = element;
else if (first < last)
{
a[last+1] = a[last];
insertInOrder(element, a, first, last-1);
}
else // first == last and element < a[last]
{
a[last+1] = a[last];
a[last] = element;
}
}
void insertion_sort_recur(int *arr, int first, int last)
{
if(first < last)
{
insertion_sort_recur(arr, first, last-1); // avoids looping thru arr[0..last-1]
insertInOrder(arr[last], arr, first, last-1); // considers arr[last] as the first element in the unsorted list
}
}
void main()
{
int A[]={5,3,2,4,6,1};
insertion_sort_recur(A,0,5);
}
I have two arrays side by side, one lists the different teams and the other lists the scores. I am able to sort the order of scores in descending order. Can this order then be used to move the corresponding team to the correct position of the leader board? eg. move the two teams with 100 points (USA and Germany) to the top of the board
#include <stdio.h>
int main()
{
char teams[18][20]={"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[18]={43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
int i;
int j;
int a;
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
printf("\n");
for (i = 0; i < 18; ++i)
{
for (j = i + 1; j < 18; ++j)
{
if (points[i] < points[j])
{
a = points[i];
points[i] = points[j];
points[j] = a;
}
}
}
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
return 0;
}
As mentioned in a comment, the typical solution is to model your data as an array of structures, rather than separate arrays. This makes sense, since the data is associated with each other.
You'd have something like:
struct score {
const char *name;
int points;
} scores[] = {
{ "England", 43 },
{ "Ireland", 5 },
/* and so on */
};
Then you can use qsort() (or your own sorting code, if that's of interest) to sort entire structure instances, and the all the data will remain together since entire structures are being moved around.
Also arrange your teams array when sorting;
a = points[i];
b = teams[i];
points[i] = points[j];
teams[i] = teams[j];
points[j] = a;
teams[j] = b;
The obvious way (as pointed out by others) is embedding your arrays into a struct, but if you are forced to use parallel arrays you can build your own function and sort both arrays at once:
#include <stdio.h>
static int comp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static void swap(int v1[], char *v2[], int a, int b)
{
int temp1;
char *temp2;
temp1 = v1[a];
v1[a] = v1[b];
v1[b] = temp1;
temp2 = v2[a];
v2[a] = v2[b];
v2[b] = temp2;
}
static void sort(int v1[], char *v2[], int left, int right, int (*comp)(const void *, const void *))
{
int i, last;
if (left >= right) return;
swap(v1, v2, left, (left + right) / 2);
last = left;
for (i = left + 1; i <= right; i++) {
if (comp(&v1[i], &v1[left]) < 0)
swap(v1, v2, ++last, i);
}
swap(v1, v2, left, last);
sort(v1, v2, left, last - 1, comp);
sort(v1, v2, last + 1, right, comp);
}
int main(void)
{
char *teams[] = {"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[] = {43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
size_t i, n = sizeof(points) / sizeof(*points);
sort(points, teams, 0, n - 1, comp);
for (i = 0; i < n; i++) {
printf("%s->%d\n", teams[i], points[i]);
}
return 0;
}
Output:
Italy->0
Ireland->5
Sweden->11
Scotland->23
South Africa->26
Belize->32
Japan->37
England->43
Mexico->45
Uraguay->46
Australia->55
Denmark->65
Wales->77
Algeria->78
France->89
Belgium->94
Germany->100
USA->100
For a bit of fun, I'm trying to implement an iterative variant of Introsort. The default implementation looks something like this:
void introsort_loop(int *a, size_t left, size_t right, size_t threshold, size_t depth) {
while(right-left > threshold) {
if(depth == 0) {
heapsort(a, left, right);
return;
}
--depth;
int p = partition(a, left, right);
introsort_loop(p, right, depth);
right = p-1;
}
}
void introsort(int *array, size_t num, size_t threshold) {
if(num > 1) {
introsort_loop(a, 0, num-1, threshold, log2(num)*2);
insertionsort(a, num);
}
}
I'm using the glibc implementation of qsort as the basis for an iterative introsort, since qsort happens to implement an iterative quicksort.
My implementation looks like this:
#include <limits.h>
#include <math.h>
#include "introsort.h"
// Stack node declarations used to store unfulfilled partition obligations.
typedef struct {
int lo;
int hi;
} stack_node;
// The next 4 #defines implement a very fast in-line stack abstraction.
// The stack needs log (total_elements) entries (we could even subtract
// log(threshold)). Since num has type size_t, we get as
// upper bound for log (num):
// bits per byte (CHAR_BIT) * sizeof(size_t).
#define STACK_SIZE (CHAR_BIT*sizeof(size_t))
#define PUSH(low, high) ((top->lo = (low)), (top->hi = (high)), ++top)
#define POP(low, high) (--top, ((low) = top->lo), ((high) = top->hi))
#define STACK_NOT_EMPTY (stack < top)
#define SWAP(a, i, j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; }
#define PARENT(i) ((i-1)/2)
#define LEFT_CHILD(i) (((i)<<1)+1)
void heapify_i(int *a, int left, int right) {
int child, swap;
int root = left;
while((child = LEFT_CHILD(root)) <= right) {
swap = root;
if(a[swap] < a[child]) {
swap = child;
}
if(child+1 <= right && a[swap] < a[child+1]) {
swap = child+1;
}
if(swap == root) {
break;
} else {
SWAP(a, root, swap);
root = swap;
}
}
}
void heapsort_i(int *a, int left, int right) {
int start = left;
int end = right;
for(start = PARENT(end); start >= left; --start) {
heapify_i(a, start, end);
}
start = left;
while(start < end) {
SWAP(a, start, end);
heapify_i(a, start, --end);
}
}
void quicksort_i(int *a, size_t num, size_t threshold, size_t depth) {
//========== QUICKSORT ==========//
if(num > threshold) {
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH(-1, -1);
int low = 0;
int high = num-1;
int left, mid, right;
while(STACK_NOT_EMPTY) {
if(depth == 0) {
heapsort_i(a, low, high);
break;
} else {
--depth;
//========== PIVOT = MID (MEDIAN OF THREE) ==========
mid = low+(high-low)/2;
if(a[mid] < a[low]) {
SWAP(a, mid, low);
}
if(a[high] < a[mid]) {
SWAP(a, high, mid);
} else {
goto jump_qi;
}
if(a[mid] < a[low]) {
SWAP(a, mid, low);
}
jump_qi:;
//========== PARTITIONING ==========//
left = low+1;
right = high-1;
while(left < right) {
while(a[left] < a[mid]) {
++left;
}
while(a[mid] < a[right]) {
--right;
}
if(left < right) {
SWAP(a, left, right);
if(mid == left) {
mid = right;
} else if(mid == right) {
mid = left;
}
++left;
--right;
}
}
// Set up pointers for next iteration. First determine whether
// left and right partitions are below the threshold size. If so,
// ignore one or both. Otherwise, push the larger partition's
// bounds on the stack and continue sorting the smaller one.
if(right-low < threshold) {
if(high-left <= threshold) {
// ignore both small partitions
POP(low, high);
} else {
// ignore small left partition
low = left;
}
} else if(high-left <= threshold) {
// ignore small right partition
high = right;
} else if(right-low > high-left) {
// push larger left partition
PUSH(low, right);
low = left;
} else {
// push larger right partition
PUSH(left, high);
high = right;
}
}
}
}
//========== INSERTION SORT ==========//
int e, i, j;
for(i = 1; i <= num; ++i) {
e = a[i];
for(j = i-1; j >= 0 && e < a[j]; --j) {
a[j+1] = a[j];
}
a[j+1] = e;
}
}
void introsort_i(int *array, size_t num, size_t threshold) {
if(num > 1) {
quicksort_i(array, num-1, threshold, log2(num)*2);
}
}
For input of sizes 10 to 100'000random elements it appears to run fine, but when I test for a million elements, it suddenly slows down to a couple seconds, which is far too long for a single array with 1 million elements.
How do I fix this?
void heapSort(int list[], int last)
{
// Local Declarations
int sorted;
int holdData;
int walker;
// Statements
for (walker = 1; walker <= last; walker++)
reheapUp (list, walker);
// Min Heap created. Now to sort!
sorted = last;
while (sorted > 0)
{
holdData = list[0];
list[0] = list[sorted];
list[sorted] = holdData;
sorted--;
reheapDown (list, 0, sorted, moves, comparisons);
}
return;
}
void reheapUp (int heap[], int newNode)
{
// Local Declarations
int parent;
int hold;
// Create a min heap
// Statements
if (newNode)
{
parent = (newNode - 1) / 2;
if (heap[newNode] > heap[parent]) // Only change made from ascending order
{
hold = heap[parent];
heap[parent] = heap[newNode];
heap[newNode] = hold;
reheapUp (heap, parent);
}
}
return;
}
void reheapDown (int heap[], int root, int last)
{
// Local Declarations
int hold;
int leftKey;
int rightKey;
int largeChildKey;
int largeChildIndex;
// Statements
if ((root * 2 + 1) <= last)
{
// There is atleast one child
leftKey = heap[root * 2 + 1];
if ((root * 2 + 2) <= last) {
rightKey = heap[root * 2 + 2];
}
else
rightKey = -1;
// Determine which child is larger
if (leftKey > rightKey)
{
largeChildKey = leftKey;
largeChildIndex = root * 2 + 1;
}
else
{
largeChildKey = rightKey;
largeChildIndex = root * 2 + 2;
}
// Test if root > large subtree
if (heap[root] < heap[largeChildIndex])
{
// parent < child
hold = heap[root];
heap[root] = heap[largeChildIndex];
heap[largeChildIndex] = hold;
reheapDown(heap, largeChildIndex, last);
}
}
return;
}
I got ascending order to heap sort to function by creating a max heap. I read that to create a descending order heap sort I need to create a min heap which I did as shown by changing heap[newNode] < heap[parent] to heap[newNode] > heap[parent] as shown in the code. However, it is still out order. Therefore, I wanted to do what are the other steps? Do I need to alter reheapDown somehow as well?
You need to change all value comparisons you make like heap[root] < heap[largeChildIndex] you didn't mention you changed.
First of all you need to change every comparison operators accordingly, just take them all and think of the problem.
Secondly you only have to reheapUp to (last/2) to create the heap, because the key at (last/2+1) doesn't have any childs.
And I made some heap-sort in C before and I had way less lines of code, and only had one "heapify" function. You might want to look at your code and try to simplify things.
EDIT : if you want some inspiration here is what I did
void fixHeap(int position,int length)
{
int child = (2*position)+1;
int temp;
while (child<=length)
{
if (child<length && vector[child]<vector[child+1])
{
child++;
}
if (vector[position]<vector[child])
{
temp = vector[position];
vector[position] = vector[child];
vector[child] = temp;
position = child;
child = (2*position)+1;
}
else
{
return;
}
}
}
void heapSort(int vector[],int N)
{
int counter;
int temp;
for (counter=(N-1)/2; counter>=0; counter--)
{
fixHeap(counter,N-1);
}
for (counter=N-1; counter>0; counter--)
{
temp = vector[counter];
vector[counter] = vector[0];
vector[0] = temp;
fixHeap(0,counter-1);
}
}
Here is heap sort using min heap implementation. Have a look, if it helps!
#include "stdafx.h"
#define LEFT(i) (2 * (i))
#define RIGHT(i) (((2 * (i)) + 1))
#define PARENT(i) ((i) / 2))
void print_heap(int input[], int n)
{
int i;
printf("Printing heap: \n");
for (i = 0; i < n; i++)
printf("%d ", input[i]);
printf("\n");
}
void swap_nodes(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void min_heapify(int input[], int i, int n)
{
int least;
int l = LEFT(i + 1) - 1; // Get 0 based array index
int r = RIGHT(i + 1) - 1; // Get 0 based array index
if (l < n && input[l] < input[i]) {
least = l;
} else {
least = i;
}
if (r < n && input[r] < input[least]) {
least = r;
}
if (least != i) {
swap_nodes(&input[i], &input[least]);
min_heapify(input, least, n);
}
}
void heapify(int input[], int n)
{
for (int i = n/2; i >= 0; i--)
min_heapify(input, i, n);
}
void heap_sort(int input[], int n)
{
heapify(input, n);
for (int i = n - 1; i >= 1; i--) {
swap_nodes(&input[0], &input[i]);
n = n - 1;
min_heapify(input, 0, n);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int input[] = {5, 3, 17, 10, 84, 19, 6, 22, 9, 1};
int n = sizeof(input) / sizeof(input[0]);
print_heap(input, n);
heap_sort(input, n);
print_heap(input, n);
return 0;
}