I got a homework, to create a Strand sort algorithm in C++, but I'm not allowed to use lists, only arrays. I have trouble understanding the algorithm, because it was never explained to me, and Google yields limited information on this subject.
I've tried my best porting the code I found on Wikipedia, from PHP to C++, but It's not working correctly. It doesn't sort the array.
Here is my code, I know a lot of it is probably badly written, but it's the best I could do with my knowledge.
#include <iostream>
using namespace std;
void echoArray(int a[], int n) {
for(int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
}
//removes an element from array
int* array_remove(int* a, int& n, int index) {
int p = 0;
int* newArray = new int[n - 1];
for(int i = 0; i < n; i++) {
if(i != index) {
newArray[p] = a[i];
p++;
}
}
n--;
return newArray;
}
//adds an element to the end of an array
int* array_append(int* a, int& n, int el) {
int* newArray = new int[n+1];
int i = 0;
for(; i < n; i++) {
newArray[i] = a[i];
}
if(n == 0)
i = 0;
newArray[i] = el;
n++;
return newArray;
}
//inserts an element (el) to index p
int* array_insert(int* a, int& n, int p, int el) {
int c = 0;
n++;
int* newArray = new int[n];
for(int i = 0; i < n; i++) {
if(i != p) {
newArray[i] = a[c];
c++;
} else {
newArray[i] = el;
}
}
return newArray;
}
int* strandSort(int* a, int n) {
int arrC = n;
int resC = 0;
int subC = 0;
int* result = new int[1];
while(arrC > 0) {
subC = 0;
int* sublist = new int[1];
sublist = array_append(sublist, subC, a[0]);
a = array_remove(a, arrC, 0);
for(int i = 0; i < arrC; i++) {
if(a[i] > sublist[subC - 1]) {
sublist = array_append(sublist, subC, a[i]);
a = array_remove(a, arrC, i);
i--;
}
}
if(resC > 0) {
for(int i = 0; i < subC; i++) {
bool spliced = false;
for(int j = 0; j < resC - 1; i++) {
if(sublist[i] > result[j]) {
result = array_insert(result, resC, i, sublist[i]);
spliced = true;
break;
}
}
if(!spliced) {
result = array_append(result, resC, sublist[i]);
}
}
} else {
result = sublist;
resC = subC;
}
}
echoArray(result, resC);
return result;
}
int main() {
int a[] = {3, 20, 6, 1, 19, 21, 6, 11, 25, 6, 0, 1, 8, 7, 29, 26, 10, 29, 9, 5};
int n = 20;
strandSort(a, n);
return 0;
}
Also, I realize that arrays are passed by reference.
Use cout<< to target the problem
After read the wiki of Strand Sort, we know there is two parts of this algorithm.
Take out a relatively sorted list
Merge it with the result list
So you need to find which part is wrong, just add
cout << "step1: sublist = ";
echoArray(sublist, subC);
before if(resC > 0) { we will see step1 is right or wrong.
Add
cout << "step2: result = ";
echoArray(result, resC);
In the bottom of the while(arrC > 0) {} loop to check step2.
Get:
step1: sublist = 3 20 21 25 29
step2: result = 3 20 21 25 29
step1: sublist = 6 19 26 29
step2: result = 6 19 26 29 3 20 21 25 29
step1: sublist = 1 6 11
step2: result = 6 19 11 26 29 3 20 21 25 29
step1: sublist = 6 8 10
step2: result = 6 8 10 19 11 26 29 3 20 21 25 29
step1: sublist = 0 1 7 9
step2: result = 6 8 7 9 10 19 11 26 29 3 20 21 25 29
step1: sublist = 5
step2: result = 6 8 7 9 10 19 11 26 29 3 20 21 25 29 0
As we can see step1 is always right but the merge step is wrong.
So we will focus the code in if(resC > 0) {} block.
Read the code carefully
If you read your code carefully you will find in for(int j = 0; j < resC - 1; i++) { the i++ is nonsense.
And the merge step has many bugs, you need to rethink about it.
The fixed code of step 2:
if(resC > 0) {
int j = 0;
for(int i = 0; i < subC; i++) {
bool spliced = false;
for(;j < resC; j++) {
if(sublist[i] < result[j]) {
result = array_insert(result, resC, j++, sublist[i]);
spliced = true;
break;
}
}
if(!spliced) {
result = array_append(result, resC, sublist[i]);
}
}
} else {
result = sublist;
resC = subC;
}
Related
my task is to sort an array by the smallest digit of a number using selection sort. for example: 61 < 35, because 1 < 3. in case of coincidence of digits, i have to print the smallest of 2.
so this is my code:
#include <iostream>
#include <time.h>
using namespace std;
int smallestOfTwo(int a, int b) {
if (a < b) return a;
else return b;
}
int smallestDigit(int a) {
int smallDigit = 9;
while (a != 0) {
if (a % 10 < smallDigit) {
smallDigit = a % 10;
}
a /= 10;
}
return smallDigit;
}
void selectionSort(int arr[], const int size) {
for (int i = 0; i < size - 1; i++) {
int min = i;
for (int j = i + 1; j < size; j++) {
if (smallestDigit(arr[j]) == smallestDigit(arr[min])) min = smallestOfTwo(j, min);
else if (smallestDigit(arr[j]) < smallestDigit(arr[min])) min = j;
}
if (min != i) {
swap(arr[min], arr[i]);
}
}
}
int main() {
srand(time(NULL));
const int size = 5;
int arr[size];
for (int i = 0; i < size; i++) {
arr[i] = rand() % 201;
cout << arr[i] << " ";
}
cout << "\n--------------------------------------------------------------------------------------\n";
selectionSort(arr, size);
for (int i = 0; i < size; i++) cout << arr[i] << " ";
return 0;
}
the problem is that for some numbers it works (for example, for 23 63 70 37 183 the output is correct: 70 183 23 37 63), but for some it doesnt work(for example, 27 26 156 178 47. the output is 156 178 27 26 47, but it should be 156 178 26 27 47 instead) and i cant figure out why. any help would be appreciated. thanks!
26 and 27 both have smallest digit 2, so they are equivalent and can be in any order in the result. To preserve original order, you can try looking up algorithms for "stable sort." To fall back on second smallest digit, third smallest digit, etc. you can count each digit and compare.
struct digit_counts {
int counts[10];
};
digit_counts convert(int a) {
digit_counts out = {};
while (a != 0) {
++out.counts[a % 10];
a /= 10;
}
return out;
}
bool operator<(const digit_counts& dc1, const digit_counts& dc2) {
for (int i = 0; i < 10; ++i) {
if (dc1.counts[i] > dc2.counts[i]) {
return true;
}
else if (dc2.counts[i] > dc1.counts[i]) {
return false;
}
}
return false;
}
If you want to fall back on the smaller of the two, then write your own comparison function.
bool special_less_than(int a, int b) {
int small_digit_a = smallestDigit(a);
int small_digit_b = smallestDigit(b);
if (small_digit_a < small_digit_b) {
return true;
}
else if (small_digit_a > small_digit_b) {
return false;
}
else {
return a < b;
}
}
My problem is this:
"Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17."
And wrote this code:
#include<iostream>
#include<iterator>
template<int N>
bool adding(int (&list)[N], int k) {
//get size of array
int length = (sizeof(list) / sizeof(list[0]));
std::cout << k << std::endl;
bool a = false;
//init 2 pointer on array
int *p1;
p1 = &list[0];
int *p2;
p2 = &list[0];
int sum = 0;
int lengthNew = length;
//check if p1+p2 = k
for (int i = 0; i < length; i++) {
for (int j = 0; j < lengthNew; j++) {
sum = *p1 + *p2;
if (p1 == p2) {
p2++;
j++;
}
else if (sum == k) {
std::cout << sum << " = " << k << "\t*p1= " <<*p1<<"\t*p2= "<< *p2 << std::endl;
a = true;
}
p2++;
}
p2 = p2 - length;
p1++;
}
return a;
}
int main() {
int myInts[] = { 19,1,2,18,13,4,10,5,5,12,7,10,8,16 };
int k = 21;
adding(myInts, k);
int w;
std::cin >> w;
return 0;
}
I get this output:
21 = 21 *p1= 19 *p2= 2
21 = 21 *p1= 2 *p2= 19
21 = 21 *p1= 13 *p2= 8
21 = 21 *p1= 5 *p2= 16
21 = 21 *p1= 5 *p2= 16
21 = 21 *p1= 8 *p2= 13
21 = 21 *p1= 16 *p2= 5
21 = 21 *p1= 16 *p2= 5
As you can see there are always two equal outputs. I know that it's because I am settin p2 back to the beginning, but I don't know how to do it otherwise. Could someone show me how to bypass the redundant information? I thought that i could save the addresses of the outputs and compare if this combination is already used. But I think it's not a good solution.
Because addition is commutative, you don't have to go through the whole array for every element.
It's enough to check all the elements after the element you're currently checking.
bool adding(const std::vector<int>& list, int k) {
bool result = false;
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
int sum = list[i] + list[j];
if (sum == k) {
std::cout << sum << " = " << k << "\tn1= " <<list[i]<<"\tn2= "<< list[j] << std::endl;
result = true;
}
}
}
return result;
}
Each pair of elements will be only compared once now.
I did this program in class and I'm trying to recreate it for an exam coming up. The program is supposed to be an array[2][10] and is supposed to output numbers in this order:
1 3 5 7 9 11 13 15 17 19
0 2 4 6 8 10 12 14 16 18
I'm really lost on this and I could really use any help.
#include<iostream>
#include <string>
#include <cstring>
using namespace std;
void out(int n[2][10]);
void fillit(int n[2][10]);
int main(){
int nums[2][10];
fillit(nums);
out(nums);
}
void fillit(int n[2][10]){
n[0][0] = 1;
n[1][0] = 0;
for (int i = 1; i < 10; i++){
n[0][i] = n[0][i] + 2;
n[1][i] = n[0][i] + 2;
}
}
void out(int n[2][10]){
for (int r = 0; r <= 1; r++){
for (int c = 0; c <= 9; c++){
cout << n[r][c];
}
cout << endl;
}
}
Update I have the program successfully filling the array but now I need the program to swap row 1 with row 2 and then output the new array. I.e.
0 2 4 6 8 10 12 14 16 18
1 3 5 7 9 11 13 15 17 19
void fillit(int n[2][10]){
for (int i = 0; i < 10; i++){
n[0][i] = (i * 2 ) + 1;
n[1][i] = i * 2;
}
}
#include<iostream>
#include <string>
#include <cstring>
using namespace std;
void out(int n[2][10]);
void fillit(int n[2][10]);
int main(){
int nums[2][10];
fillit(nums);
out(nums);
}
void fillit(int n[2][10]){
n[0][0] = 1;
n[1][0] = 0;
for (int i = 1; i < 10; i++){
n[0][i] = n[0][i-1] + 2;
n[1][i] = n[0][i-1] + 2;
}
}
void out(int n[2][10]){
for (int r = 0; r <= 1; r++){
for (int c = 0; c <= 9; c++){
cout << n[r][c];
}
cout << endl;
}
}
How about this, its shorter?
int nums[2][10];
for (int i = 0; i < 20; i++)
{
nums[(i%2)^1][i/2] = i;
}
I noticed that second array elements are even numbers, and the first array corresponding elements are one bigger (and thus odd) ... so this answer accomplishes using ONLY addition. Might be easier to understand.
void fillit(int n[2][10])
{
int even = 0; // start value
for (size_t i = 0; i < 10; i++)
{
int odd = even + 1;
n[0][i] = odd;
n[1][i] = even;
even += 2;
}
}
I noticed that you tagged this problem with C++. Perhaps you should try vectors.
For small vectors, you simply declare with initial values in curly-braces, making it easy to define the matrix limits [2] and [10]. In this example, I initialized using easy to recognize values, so you can tell the 2x10 matrix has not yet been filled. Without this init, the values contained will be random noise.
std::vector<std::vector<int>> n {
{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, // row 1
{ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 } // row 2
// 1 2 3 4 5 6 7 8 9 10 <-- col
};
Yes, you could write in the target value of your output, but then fillit() would not be needed.
For passing the 2x10 vector to fillIt(), remember that you need to mark the matrix as a reference. The following emphasizes that n[0] contains odd numbers, and n[1] contains 10 even numbers.
// vector x vector v--reference
void fillIt(std::vector<std::vector<int>>& n)
{
int even = 0;
for (size_t c = 0; c < 10; ++c) // row major {
int odd = even + 1;
n[0][c] = odd;
n[1][c] = even;
even += 2;
}
}
For test, I recommend just passing the 2x10 vector to a new function "showIt()".
// do not modify--vvvvv do not copy--v
void vec2x10Show (const std::vector<std::vector<int>>& n)
{
// header
std::cout << "\nCOL->";
for (int i=0; i<10; ++i) std::cout << std::setw(3) << i+1 << " ";
std::cout << "\nr1: "; // r c
for (int c=0; c<10; ++c) std::cout << std::setw(3) << n[0][c] << " ";
std::cout << "\nr2: "; // r c
for (int c=0; c<10; ++c) std::cout << std::setw(3) << n[1][c] << " ";
std::cout << std::endl;
}
Note the hard coded '10' in each loop (a magic number). Using vectors, this magic number is not necessary because the vector includes this information (your next assignment).
I am writing a program to build a heap array from a usual array and it just doesn't work.
We have to use this sudo code which I used to write my rebuildHeap function but I don't know what I am doing wrong. Could someone spot any mistakes?
rebuildHeap is used after the replacement node has taken the place of root
rebuildHeap(heap, index, lastIndex)
1 if (index * 2 + 1 <= lastIndex)
1 leftKey = heap[index*2+1].key
2 if (index * 2 + 2 > lastIndex)
1 largeChildIndex = index * 2 + 1
3 else
1 rightKey = heap[index*2+2].key
2 if (leftKey > rightKey)
1 largeChildIndex = index * 2 + 1
3 else
1 largeChildIndex = index * 2 + 2
4 end if
4 end if
5 if (heap[index].key < heap[largeChildIndex].key)
1 swap (heap[index], heap[largeChildIndex])
2 rebuildHeap(heap, largeChildIndex, lastIndex)
6 end if
2 end if
and this is my code.. so first I create an array of int and store some random values then I run create heap function which calls rebuildHeap till heap array is complete.
EDITED, removed the array size..
void rebuildHeap(int heap[], int index, int lastindex) {
int leftkey = 0 ;
int largeChildIndex = 0;
int rightkey = 0;
cout << endl;
if (heap[index*2+1] <= heap[lastindex])
{
leftkey = heap[index*2+1];
cout <<" index : " << index*2+1 << " leftkey " << leftkey << endl;
cout <<" index : " << lastindex << " heap[lastindex] = " << heap[lastindex] << endl;
if ((heap[index * 2+ 2]) > heap[lastindex])
largeChildIndex = (index* 2) +1;
else
{
rightkey = heap[index*2+2];
if (leftkey > rightkey)
largeChildIndex = index * 2 +1;
else
largeChildIndex = index*2+2;
}
}
if (heap[index] < heap[largeChildIndex]) {
swap(heap[index], heap[largeChildIndex]);
rebuildHeap(heap, largeChildIndex, lastindex);
}
}
void swap (int &a, int &b) {
int temp = b;
b = a;
a = temp;
}
int main(int argc, const char * argv[])
{
int a[] = {3, 7, 12, 15, 18, 23, 4, 9, 11, 14, 19, 21};
int length = (sizeof(a)/sizeof(a[0]));
for (int i = length/2-1; i >= 0; i-- ) {
rebuildHeap(a, i, length-1);
cout << " i " << i;
}
for (int i = 0; i < length; i++) {
cout << endl<< a[i] << endl;
}
};
First of all I would like to highlight that your translation of the pseudocode was wrong, so I fixed it.
#include <iostream>
using namespace std;
void rebuildHeap(int *heap, int index, int lastindex)
{
int leftkey = 0 ;
int largeChildIndex = 0;
int rightkey = 0;
if ((index*2 + 1) <= lastindex)
{
leftkey = heap[index*2+1];
if ((index*2 + 2) > lastindex)
largeChildIndex = index*2 +1;
else
{
rightkey = heap[index*2+2];
if (leftkey > rightkey)
largeChildIndex = index*2+1;
else
largeChildIndex = index*2+2;
}
}
else
{
return;
}
if (heap[index] < heap[largeChildIndex]) {
swap(heap[index], heap[largeChildIndex]);
rebuildHeap(heap, largeChildIndex, lastindex);
}
}
void swap (int &a, int &b) {
int temp = b;
b = a;
a = temp;
}
int main(int argc, const char * argv[])
{
int a[] = {3, 7, 12, 15, 18, 23, 4, 9, 11, 14, 19, 21};
int length = sizeof(a)/sizeof(a[0]);
//create heap
for (int i = (length/2-1); i >= 0; i --)
{
rebuildHeap(a, i, length-1);
}
//prints the heap array
for (int i = 0; i < length; i++) {
cout << a[i] << " ";
}
return 0;
}
Here is the output: 23 19 21 15 18 12 4 9 11 14 7 3
My understanding of heap is like 0 so I'm not sure what is your expected output.
As part of a homework assignment, I need to be able to implement a merge sort using a structure as the main argument. Having not been familiar with the merge sort until today, i have attempted to write my own implementation of it. For some reason I cannot get it to work.
Here is my code:
#include<iostream>
#include<stdlib.h>
using namespace std;
struct MergeArgument
{
int *numArray;
int *tempArray;
int lowIndex, highIndex;
};
void merge(MergeArgument*);
void merge_sort(MergeArgument*);
int main(int argc, char** argv)
{ int SIZE = 25;
MergeArgument arg;
int arr[SIZE];
int temp[SIZE];
for(int k = 0; k < SIZE; k++)
{
arr[k] = rand() % 100;
cout << arr[k] << " ";
}
arg.numArray = arr;
arg.tempArray = temp;
arg.lowIndex = 0;
arg.highIndex = SIZE - 1;
cout << endl;
merge_sort(&arg);
cout << "Sorted array: \n";
for (int i = 0; i < SIZE; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
void merge_sort(MergeArgument *arg)
{ int tempHigh, tempLow;
if(arg->lowIndex < arg->highIndex)
{
tempHigh = arg->highIndex;
tempLow = arg->lowIndex;
arg->highIndex = (tempHigh + tempLow) / 2;
merge_sort(arg);
arg->highIndex = tempHigh;
arg->lowIndex = ((tempHigh + tempLow) / 2) + 1;
merge_sort(arg);
arg->lowIndex = tempLow;
merge(arg);
}
}
void merge(MergeArgument *arg)
{ int low = arg->lowIndex, mid = ((arg->lowIndex + arg->highIndex) / 2), high = arg->highIndex;
int i = low, lowCounter = low, highCounter = mid + 1;
while((lowCounter <= mid) && (highCounter <= high))
{
if(arg->numArray[lowCounter] < arg->numArray[highCounter])
{
arg->tempArray[i] = arg->numArray[lowCounter];
lowCounter++;
}
else
{
arg->tempArray[i] = arg->numArray[highCounter];
highCounter++;
}
i++;
}
if (lowCounter < mid)
{
for (int k = lowCounter; k < mid; k++)
{
arg->tempArray[i] = arg->numArray[k];
i++;
}
}
else
{
for (int k = highCounter; k <= arg->highIndex; k++)
{
arg->tempArray[i] = arg->numArray[k];
i++;
}
}
for(int k = arg->lowIndex; k <= arg->highIndex; k++)
{
arg->numArray[k] = arg->tempArray[k];
}
}
Here is the output I am getting:
83 86 77 15 93 35 86 92 49 21 62 27 90 59 63 26 40 26 72 36 11 68 67 29 82
Sorted array:
11 -1216235240 15 0 21 26 -1079135248 26 27 -1079135396 29 -1216770650 35 -1216235240 49 -1216492084 59 0 68 72 82 83 0 86 82
Can anyone point out what exactly I am doing wrong?
This is pretty close to working, although you might want to consider some of the comments folks have made on making this more C++ like. No doubt this is from hard-won experience that there is never enough time to go back and do what you really should do.
The problem I see is here, in merge:
if (lowCounter < mid)
{
for (int k = lowCounter; k < mid; k++)
{
arg->tempArray[i] = arg->numArray[k];
i++;
}
}
You might want to compare and contrast the bounds here to the initial loop.