Trying to implement HeapSort - c++

I am getting stuck on heapSort. I have some code but I think its pretty wrong since I'm having hard time compiling it. Any suggestions? Heap sort should be fairly easy to implement but I have bunch of syntax errors. Here's my code:
/* Framework for Heap Sort
* CS333 Spring 2011
*
*/
#include <stdio.h>
#define MAX_SIZE 1000000
int data[MAX_SIZE];
int n;
int j;
int parent(int j) {
if(j==1)
return 0;
if(j%2==0)
return ( (j / 2)-1);
else
return ( (j / 2));
}
int left(int j) {
return (2 * j) + 1;
}
int right(int j) {
return (2 * j) + 2;
}
void heapify(int data[], int j) {
int l = left(j), great;
int r = right(j);
if ( (data[l] > data[j]) && (l < sizeof(data))) {
great = l;
}
else {
great = j;
}
if ( (data[r] > data[great]) && (r < sizeof(data))) {
great = r;
}
if (great != j) {
int temp = data[j];
data[j] = data[great];
data[great] = temp;
heapify(data, great);
}
}
int BuildMaxHeap(int data[]) {
for (int j = (sizeof(data) - 1) / 2; j >= 0; j--) {
heapify(data, j);
return data;
}
}
void HeapSort(int data[]) {
BuildMaxHeap(data);
for (int j = sizeof(data); j > 0; j--) {
int temp = data[0];
data[0] = data[data.sizeof() - 1];
data[sizeof(data) - 1] = temp;
sizeof(data) = sizeof(data) - 1;
heapify(data, 0);
}
}
int main()
{
int i;
/* Read in the data */
n = 0;
while (scanf("%d", &data[n]) == 1)
++n;
/* Sort the numbers low to high */
HeapSort(data);
/* Print out the data */
for (i = 0; i < n; ++i)
printf("%d", data[i]);
}

Most of your problems seem to be in your HeapSort routine:
void HeapSort(int data[]) {
BuildMaxHeap(data);
for (int j = sizeof(data); j > 0; j--) {
When you pass an array to a function like this, what the function receives is actually a pointer. Using sizeof on that pointer will not tell you about the size of the data pointed to by the pointer -- it'll just tell you how many bytes the pointer itself occupies (typically 4). You probably want to pass the array size as a parameter:
void HeapSort(int *data, size_t data_size) {
and throughout the rest of the routine, you'll refer to data_size, not sizeof(data).
int temp = data[0];
data[0] = data[data.sizeof() - 1];
data[sizeof(data) - 1] = temp;
sizeof(data) = sizeof(data) - 1;
sizeof(whatever) is also essentially a constant, not a variable; you can't use it as the target of an assignment (but, again, using data_size as suggested above will let you do the assignment).

Related

What is wrong with my merge sort implementation refer to CLRS?

I tried to implement merge sort using C++, however, something went wrong. I have no idea what is wrong.
The following code is what I wrote based on CLRS. I think it is quite easy to understand the meaning.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& nums, int p, int q, int r);
void mergeSort(vector<int>& nums, int p, int r){
if (p < r) {
int q = (p + r) / 2;
mergeSort(nums, p, q);
mergeSort(nums, q + 1, r);
merge(nums, p, q, r);
}
}
void merge(vector<int>& nums, int p, int q, int r) {
int s1 = p, s2 = q + 1;
vector<int> l1, l2;
for (int i = s1; i <= q; i++) {
l1.push_back(nums[i]);
}
for (int i = s2; i <= r; i++) {
l2.push_back(nums[i]);
}
int left = 0, right = 0;
int idx = 0;
while (left < l1.size() && right < l2.size()) {
if (l1[left] < l2[right]) {
nums[idx] = l1[left++];
}
else {
nums[idx] = l2[right++];
}
idx++;
}
while (left < l1.size()) {
nums[idx++] = l1[left++];
}
while (right < l2.size()) {
nums[idx++] = l2[right++];
}
}
int main() {
vector<int> vect;
vect.push_back(1);
vect.push_back(3);
vect.push_back(12);
vect.push_back(23);
vect.push_back(4);
vect.push_back(11);
vect.push_back(44);
vect.push_back(322);
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
return 0;
}
I want to use the program to sort some integers, however, it only shows many duplicate numbers. What's going on? I don't think there is a problem of the merge function.
The code needs a one line fix:
int idx = p; // not idx = 0
Optimized top down using arrays from Wiki article (note bottom up is slightly faster):
void TopDownMerge(int A[], int bgn, int mid, int end, int B[])
{
int i, j, k;
i = bgn, j = mid, k = bgn;
while(1){
if(A[i] <= A[j]){ // if left smaller
B[k++] = A[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue
do // else copy rest of right run
B[k++] = A[j++];
while(j < end);
break; // and break
} else { // else right smaller
B[k++] = A[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue
do // else copy rest of left run
B[k++] = A[i++];
while(i < mid);
break; // and break
}
}
}
void TopDownSplitMerge(int B[], int bgn, int end, int A[])
{
if (end - bgn <= 1) // if run size == 1
return; // consider it sorted
int mid = (end + bgn) / 2;
TopDownSplitMerge(A, bgn, mid, B);
TopDownSplitMerge(A, mid, end, B);
TopDownMerge(B, bgn, mid, end, A);
}
void TopDownMergeSort(int A[], int n) // n = size (not size-1)
{
if(n < 2)
return;
int *B = new int [n]; // 1 time allocate and copy
for(size_t i = 0; i < n; i++)
B[i] = A[i];
TopDownSplitMerge(B, 0, n, A); // sort data from B[] into A[]
delete B;
}
Afterwards, I finally get to fix the bugs of my program. After modification, here is the code:
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp.resize((int)nums.size(), 0);
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int start, int end) {
if (start >= end) return;
int middle = (start + end) / 2;
mergeSort(nums, start, middle);
mergeSort(nums, middle + 1, end);
merge(nums, start, middle, end);
}
void merge(vector<int>& nums, int leftStart, int middle, int rightEnd) {
int leftEnd = middle;
int rightStart = middle + 1;
int i = leftStart, j = rightStart;
int index = 0;
while (i <= leftEnd && j <= rightEnd) {
if (nums[i] < nums[j]) {
temp[index] = nums[i++];
}
else {
temp[index] = nums[j++];
}
index++;
}
while (i <= leftEnd) {
temp[index++] = nums[i++];
}
while (j <= rightEnd) {
temp[index++] = nums[j++];
}
for (int i = 0; i < rightEnd - leftStart + 1; i++) {
nums[i + leftStart] = temp[i];
}
}
};
Here is something should be careful next time:
In the merge part, it is difficult to merge in place. It'd be better to use another temp array to store the merged results and update to the target array (nums in this case).
Readable identifers is very recommended (Although the pseudocode of CLRS may not use that part).
Need to use debuggers to find the bug of program {However, it takes like forever to load local variables of VS Code debugers.

Is there any problem with this implementation of the Merge Sort algorithm? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I know there are many implementations of the merge sort algorithm. I have implemented the following code according to the algorithm provided in the book Introduction to Algorithms by CLRS.
void merge_sort(int arr[], int starting_index, int ending_index) {
if(starting_index < ending_index) {
int middle_index = (starting_index + ending_index)/2;
merge_sort(arr, starting_index, middle_index);
merge_sort(arr, middle_index+1, ending_index);
merge_the_parts(arr, starting_index, middle_index, ending_index);
}
}
void merge_the_parts(int arr[], int starting_index, int middle_index, int ending_index) {
int length_of_first_array = middle_index - starting_index + 1;
int length_of_second_array = ending_index - middle_index;
const int sentinel = INT_MAX;
int left_arr[length_of_first_array + 1];
int right_arr[length_of_second_array + 1];
for(int i=0; i<length_of_first_array; i++) {
left_arr[i] = arr[starting_index + i];
}
// building second auxilliary
for(int i=0; i<length_of_second_array; i++) {
right_arr[i] = arr[(middle_index+1) + i];
}
left_arr[length_of_first_array] = sentinel; // use the sentinel as a condition
right_arr[length_of_second_array] = sentinel;
int i=0;
int j=0;
// the main merging loop
for(int k=starting_index; k<ending_index+1; k++) {
if(left_arr[i] <= right_arr[j]) {
arr[k] = left_arr[i];
i++;
}
else {
arr[k] = right_arr[j];
j++;
}
}
}
The code works fine for sorting the array and inversion count. But it gives the wrong answer to this problem - https://www.spoj.com/problems/DCEPC206/. I have used the following code for the problem.
# include <iostream>
# include <climits>
using namespace std;
long int merge(int *arr, int l, int mid, int r) {
int n1 = mid - l + 1;
int n2 = r - mid;
int *arrL = new int[n1 + 1];
int *arrR = new int[n2 + 1];
for(int i=0; i<n1; i++) {
arrL[i] = arr[l + i];
}
for(int j=0; j<n2; j++) {
arrR[j] = arr[(mid + 1) + j];
}
arrL[n1] = INT_MAX;
arrR[n2] = INT_MAX;
int i = 0, j = 0;
long int count = 0;
for(int k=l; k<=r; k++) {
if(arrL[i] < arrR[j]) {
arr[k] = arrL[i];
if(arrR[j] != INT_MAX) {
count += (arrL[i] * (n2 - j));
}
i++;
} else {
arr[k] = arrR[j];
j++;
}
}
delete[] arrL;
delete[] arrR;
return count;
}
long int countSeries(int *arr, int l, int r) {
long int count = 0;
if(l < r) {
int mid = (l + r) / 2;
count += countSeries(arr, l, mid);
count += countSeries(arr, mid + 1, r);
count += merge(arr, l, mid, r);
return count;
}
return count;
}
You're getting wrong answer because you're using just a long to hold such large value of count considering the ranges given in the problem.
Use long long which can hold the large value and not overflow:
long long count = 0;,
long long countSeries(int *arr, int l, int r) {,
count += (long long)arrL[i] * (n2 - j);
Here's a running code

sort visualizer bug in c++ using quicksort

so when I create this sorting visualiser using a game making library called splashkit, ( I know its not ideal but its what my course is teaching me in) I am trying to show the entire array and show each individual swap. But instead it is doing this: Video of my bug
I am not making sense of the logic of my code as I followed a tutorial to achieve this. The sort itself is fine and works great however the drawing of the rectangles is weird, and not what im trying to achieve.
I would like to achieve something like this. (Without the colors/sound effects).
CODE UPDATED:
#include "splashkit.h"
#define NUM_VALS 200
void draw_values(const int values[], int size)
{
int x = 0;
int y;
int rect_height;
int rect_width = screen_width() / size;
for (int i = 0; i < size; i++)
{
rect_height = values[i];
y = screen_height() - rect_height;
fill_rectangle(COLOR_RED, x, y, rect_width, rect_height);
draw_rectangle(COLOR_WHITE, x, y, rect_width, rect_height);
x += rect_width;
}
}
void draw_sort(int values[], int size)
{
clear_screen(COLOR_WHITE);
draw_values(values, size);
refresh_screen(60);
}
void swap (int &value1, int &value2)
{
int temp = value1;
value1 = value2;
value2 = temp;
}
/* inspiration/educated from https://www.geeksforgeeks.org/quick-sort/ */
int partition (int values[], int low, int size)
{
int pivot = values[size]; // the pivot value
int i = (low - 1); // currently selected element
// work out if all values have become the pivot value, loop until all have.
for (int j = low; j <= size-1; j++)
{
if (values[j] <= pivot)
{
i++;
swap(values[i], values[j]);
draw_sort(values, size);
}
}
swap(values[i + 1], values[size]);
draw_sort(values, size);
return (i+1);
}
void quick_sort (int values[], int low, int size)
{
if (low < size)
{
// This is the partitioning index for quick sorting
int pi = partition(values, low, size);
// This sorts small partitions at a time then sorts them together.
quick_sort(values, low, (pi - 1));
quick_sort(values, (pi + 1), size);
}
}
void bubble_sort(int values[], int size)
{
for (int j = 0; j < size; j++)
{
for (int i = 0; i < size - 1; i++)
{
if (values[i] > values[i + 1])
{
swap(values[i], values[i + 1]);
draw_sort(values, size);
}
}
}
}
void random_fill_array(int values[], int size)
{
for (int i = 0; i < size; i++)
{
values[i] = rnd(screen_height()) + 1;
}
}
void handle_input(int values[], int size)
{
if (key_typed(R_KEY))
{
random_fill_array(values, size);
}
else if (key_typed(S_KEY))
{
bubble_sort(values, size);
}
else if (key_typed(D_KEY))
{
quick_sort(values, 0, size);
}
}
int main()
{
int values[NUM_VALS];
open_window("Sort Visualiser", 800, 600);
random_fill_array(values, NUM_VALS);
while ( not quit_requested() )
{
process_events();
handle_input(values, NUM_VALS);
draw_sort(values, NUM_VALS);
}
return 0;
}
Inside the quick_sort function, size is not the size of the list its the size of the current partition, therefore you only draw the current partition not the whole list when you call draw_sort. You need to add extra parameters with the original list size:
int partition (int values[], int low, int partitionSize, int size)
{
int pivot = values[partitionSize]; // the pivot value
int i = (low - 1); // currently selected element
// work out if all values have become the pivot value, loop until all have.
for (int j = low; j <= partitionSize-1; j++)
{
if (values[j] <= pivot)
{
i++;
swap(values[i], values[j]);
draw_sort(values, size);
}
}
swap(values[i + 1], values[partitionSize]);
draw_sort(values, size);
return (i+1);
}
void quick_sort (int values[], int low, int partitionSize, int size)
{
if (low < partitionSize)
{
// This is the partitioning index for quick sorting
int pi = partition(values, low, partitionSize, size);
// This sorts small partitions at a time then sorts them together.
quick_sort(values, low, (pi - 1), size);
quick_sort(values, (pi + 1), partitionSize, size);
}
}

In c++ take an integer array (arr[]), its length (N), and the number of elements to right-shift (M):?

How can I finish my code to take an integer array (arr[]), its length (N), and the number of elements to right-shift (M).
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void shiftright (int myarray[], int size);
int main (void)
{
int myarray [] = {1, 2, 3, 4, 5};
shiftright( myarray, 5);
for ( int i = 0; i < 5; i++)
{
cout << myarray[i] << ' ';
}
return (0);
}
void shiftright (int myarray[], int size, int M)
{
for (int m = (size - 1); m >= 1; m--) {
int temp = myarray[size - 1];
for (int i = (size - 1); i >= 1; i--)
{
myarray[i] = myarray[i - 1] ;
}
myarray[0] = temp;
}
}
Instead of rolling your own, simply use a standard algorithm.
if (m > 0 && size > 0)
std::rotate(myarray, myarray + m % size, myarray + size);
Looks like you're trying to perform a "rotate" operation. Have you considered creating an indexer with an offset and not actually having to rotate anything at all? (This is far less costly.)
Anyways, just remove your outer loop to shift once:
void shiftright (int myarray[], int size)
{
int temp = myarray[size - 1];
for (int i = (size - 1); i >= 1; i--)
{
myarray[i] = myarray[i - 1];
}
myarray[0] = temp;
}
Now, you may create another method to shift m times:
void shiftright (int myarray[], int size, int m)
{
for (int i = 0; i < m; i++)
{
shiftright(myarray, size);
}
}
This is obviously very costly in terms of performance, so you may want to explain what you need this for.

Damerau–Levenshtein distance (Edit Distance with Transposition) c implementation

I implemented the Damerau–Levenshtein distance in c++ but it does not give correct o/p for the input (pantera,aorta) the correct o/p is 4 but my code gives 5.....
int editdist(string s,string t,int n,int m)
{
int d1,d2,d3,cost;
int i,j;
for(i=0;i<=n;i++)
{
for(j=0;j<=m;j++)
{
if(s[i+1]==t[j+1])
cost=0;
else
cost=1;
d1=d[i][j+1]+1;
d2=d[i+1][j]+1;
d3=d[i][j]+cost;
d[i+1][j+1]=minimum(d1,d2,d3);
if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] ) //transposition
{
d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
}
}
}
return d[n+1][m+1];
}
I don't see any errors. Can someone find a problem with the code?
The algorithm in the post does not compute Damerau-Levenshtein distance. In a wikipedia article this algorithm is defined as the Optimal String Alignment Distance.
A java implementation of DL distance algorithm can be found in another SO post.
To get the correct values of OSA distance please change the lines marked with - below with the lines marked with +
int editdist(string s,string t,int n,int m)
{
int d1,d2,d3,cost;
int i,j;
for(i=0;i<=n;i++)
{
for(j=0;j<=m;j++)
{
- if(s[i+1]==t[j+1])
+ if(s[i+1]==t[j+1])
cost=0;
else
cost=1;
d1=d[i][j+1]+1;
d2=d[i+1][j]+1;
d3=d[i][j]+cost;
d[i+1][j+1]=minimum(d1,d2,d3);
- if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] ) //transposition
+ if(i>0 && j>0 && s[i]==t[j-1] && s[i-1]==t[j] ) //transposition
{
d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
}
}
}
return d[n+1][m+1];
}
It looks as if the code was copied from a program written in a programming language where array indices start at 1 by default. Therefore all references to the elements of the distance array d were incremented. However the references to the characters within the strings are references to 0-based arrays, therefore they should not be updated.
To compute the distance the distance array has to be properly initialized:
for( i = 0; i < n + 1; i++)
d[i][0] = i;
for( j = 1; j < m + 1; j++)
d[0][j] = j;
Since you have got the answer 5, you probably have your distance array already initialized correctly.
Since the above algorithm does not compute the DL distance, here is a sketch of a C implementation of the DL algorithm (derived from the SO post with a java impl. derived from an ActionScript impl. in the Wikipedia article).
#define d(i,j) dd[(i) * (m+2) + (j) ]
#define min(x,y) ((x) < (y) ? (x) : (y))
#define min3(a,b,c) ((a)< (b) ? min((a),(c)) : min((b),(c)))
#define min4(a,b,c,d) ((a)< (b) ? min3((a),(c),(d)) : min3((b),(c),(d)))
int dprint(int* dd, int n,int m){
int i,j;
for (i=0; i < n+2;i++){
for (j=0;j < m+2; j++){
printf("%02d ",d(i,j));
}
printf("\n");
}
printf("\n");
return 0;
}
int dldist2(char *s, char* t, int n, int m) {
int *dd;
int i, j, cost, i1,j1,DB;
int INFINITY = n + m;
int DA[256 * sizeof(int)];
memset(DA, 0, sizeof(DA));
if (!(dd = (int*) malloc((n+2)*(m+2)*sizeof(int)))) {
return -1;
}
d(0,0) = INFINITY;
for(i = 0; i < n+1; i++) {
d(i+1,1) = i ;
d(i+1,0) = INFINITY;
}
for(j = 0; j<m+1; j++) {
d(1,j+1) = j ;
d(0,j+1) = INFINITY;
}
dprint(dd,n,m);
for(i = 1; i< n+1; i++) {
DB = 0;
for(j = 1; j< m+1; j++) {
i1 = DA[t[j-1]];
j1 = DB;
cost = ((s[i-1]==t[j-1])?0:1);
if(cost==0) DB = j;
d(i+1,j+1) =
min4(d(i,j)+cost,
d(i+1,j) + 1,
d(i,j+1)+1,
d(i1,j1) + (i-i1-1) + 1 + (j-j1-1));
}
DA[s[i-1]] = i;
dprint(dd,n,m);
}
cost = d(n+1,m+1);
free(dd);
return cost;
}
Here is my C++ version of this algorithm:
int damerau_levenshtein_distance(std::string p_string1, std::string p_string2)
{
int l_string_length1 = p_string1.length();
int l_string_length2 = p_string2.length();
int d[l_string_length1+1][l_string_length2+1];
int i;
int j;
int l_cost;
for (i = 0;i <= l_string_length1;i++)
{
d[i][0] = i;
}
for(j = 0; j<= l_string_length2; j++)
{
d[0][j] = j;
}
for (i = 1;i <= l_string_length1;i++)
{
for(j = 1; j<= l_string_length2; j++)
{
if( p_string1[i-1] == p_string2[j-1] )
{
l_cost = 0;
}
else
{
l_cost = 1;
}
d[i][j] = std::min(
d[i-1][j] + 1, // delete
std::min(d[i][j-1] + 1, // insert
d[i-1][j-1] + l_cost) // substitution
);
if( (i > 1) &&
(j > 1) &&
(p_string1[i-1] == p_string2[j-2]) &&
(p_string1[i-2] == p_string2[j-1])
)
{
d[i][j] = std::min(
d[i][j],
d[i-2][j-2] + l_cost // transposition
);
}
}
}
return d[l_string_length1][l_string_length2];
}