Linked list node equality - singly-linked-list

I'm having trouble in understanding equal sign between two nodes in a linked list.
If there are two linked list nodes n1 and n2
N1 = N2 means value of N2 is assigned to N1 node or N1 and N2 points to same location ?

Lets say your structure defined as
struct my_struct{
int val;
struct my_struct *next;
};
If N1 and N2 are structure pointer:
struct my_struct *N1, *N2;
then N1 = N2 means, N1 points to same location as N2.(The location N1 points to goes off. If it points to a dynamic memory save it to free further)
If N1 and N2 are structure variables:
struct my_struct N1, N2;
then N1 = N2 gives you a compilation error.

Related

How do I allocate an array in a function that is at the same time an input argument?

I'm busy with an assignment, but I'm not sure how to tackle a problem. As a part of a program I need to write an add function. The goal of the program is to:
Read two integer values n1 and n2 from the command line.
Allocate two integer arrays array1 and array2 of size n1 and n2
inititalize the two arrays with values 0,1....,n1-1 and 0,1....,n2-1
Write an add function with the signature:
void add(... array1, ... n1, ... array2, ... n2, ... array3, ... n3)
The function should provide the following functionality:
Allocates an interger array array3 of size n3 = max(n1,n2);
adds the two arrays array1 and array2 element by element into array3;
adds only the first min(n1,n2) elements and copies the elements from the longer array when the two arrays have different length;
returns array3 and its length n3 via the fifth and the sixth function argument, respectively. Do not change the signature of the add function.
I'm stuck at the part of the add function. I don't see how array3 must be an input argument, but also needs to be allocated in the function. The same confusion holds for n3.
I got as hint that I need to work with double pointers.
Question: How can I implement the first functionality point of the function, while keeping the function signature the same?
Many thanks in advance :)
Nadine
EDIT:
My code so far:
// Include header file for standard input/output stream library
#include <iostream>
// Your implementation of the add functions starts here...
void add(int *array1, int *array2, int **array3){
array1[5] = 20;
}
// The global main function that is the designated start of the program
int main(int argc,char* argv[]){
// Read integer values n1 and n2 from the command line
//int n1;
//int n2;
//n1 = atoi(argv[1]);
//n2 = atoi(argv[2]);
// Allocate and initialize integer arrays array1 and array2
int n1 = 10;
int n2 = 10;
int* array1 = NULL;
array1 = new int[n1];
int* array2 = NULL;
array2 = new int[n2];
for (int x = 0; x<n1; x++)
{
array1[x] = x;
}
for (int y = 0; y<n2; y++)
{
array2[y] = y;
}
int *array3;
// Test your add function
add(array1, array2, &array3);
delete[] array1;
delete[] array2;
delete[] array3;
// Return code 0 to the operating system (= no error)
return 0;
}
You need to allocate the array inside the function, but also return the allocated array through the "output parameter" array3. To return something through an output parameter, the parameter needs to be a pointer; but to return an array, the array itself is also a pointer. So what we need is indeed a pointer to a pointer:
void add(... array1, ... n1, ... array2, ... n2, int **array3, ... n3)
It would be called like this:
// Caution: uninitialized pointer at this point! Do not dereference!
int *output;
// Pass the address of the pointer.
add(..., ..., ..., ..., &output, ...);
// Now output has been initialized, so *output is valid (same as output[0]).
output is a single pointer because it contains the address of the array.
When passing this to the function add, we write &output instead of simply output. You can read this as "address of output", which is the address of the pointer, which is the address of the address of the array. This way, add can write into the pointed-to variable.
Inside add, you could do something like this to allocate the array:
*array3 = new int[n3];
Notice the extra * here: we want to store the address of the newly allocated array in the location pointed to by array3, not in array3 itself (which, after all, does not point to an array but to a pointer).
All this might become a bit easier to understand if the function returned a single float instead of an int *:
void approximate_pi(float *out) {
*out = 3.14;
}
int main() {
float pi;
approximate_pi(&pi);
}
The function accepts a pointer to a float, and writes the output into the location that the pointer points to. When calling the function, we pass the address of the desired output location.
// I am also doing that course, here is my code
// I past current self-test
// But I mistakenly clicked spec test twice before, so I only get one chance left
// Could you try the spec test on your Weblab and let me know the result?
// Include header file for standard input/output stream library
#include <iostream>
// Your implementation of the add functions starts here...
void add(int* array1, int n1, int* array2, int n2, int** array3, int& n3)
{
n3 = std::max(n1, n2);
*array3 = new int[n3];
for (int i=0; i<n3; i++)
{
if (i >= n1) {*(*array3+i) = array2[i];}
else if (i >= n2) {*(*array3+i) = array1[i];}
else {*(*array3+i) = array1[i] + array2[i];}
}
}
// The global main function that is the designated start of the program
int main()
{
// Read integer values n1 and n2 from the command line
int n1 = 9;
int n2 = 10;
// Allocate and initialize integer arrays array1 and array2
int* array1 = new int[n1];
for (int i =0; i<n1; i++) {*(array1+i) = i;}
int* array2 = new int[n2];
for (int i =0; i<n2; i++) {*(array2+i) = i;}
int* array3 = NULL;
int n3 = 0;
// Test your add function
add(array1, n1, array2, n2, &array3, n3);
std::cout<<"Array3 = " << std::endl;
for (int i=0; i < n3; i++) {std::cout<<array3[i]<<std::endl;}
std::cout<<"The length of array3 = "<< n3 << std::endl;
delete[] array1,
delete[] array2;
delete[] array3;
array1 = nullptr;
array2 = nullptr;
array3 = nullptr;
// Return code 0 to the operating system (= no error)
return 0;
}

Merging multiple sorted arrays using min heap

Looking to implement a function to merge multiple sorted arrays (of the same size) using STL's min heap. Here's what I have so far:
struct node{
int element; // the actual element that is being stored
int index; // array index from where the element was taken
int next; // next index
node(int x, int y, int z){
element = x;
index = y;
next = x;
}
bool operator<( const node & d ) const {
return element < d.element;
}
};
void multiway_merge(vector<vector<int> >& input_lists, vector<int>& output_list){
// n represents the number of unordered sublists and m is the number of integers comprising each sublist
size_t n = input_lists.size();
size_t m = input_lists[0].size();
int element;
vector<node> heap;
heap.reserve(m);
// loading first element of each sub-array into heap: (believe is correct)
for(int i = 0; i < n; i++){
node current(input_lists[i][0], i, 1);
heap.push_back(current);
}
make_heap(heap.begin(), heap.end());
for(int j = 0; j < (n*m); j++){
node root = heap[0];
output_list[j] = root.element;
if(root.next < m){ // if the next element isn't bigger than the array itself...
root.element = input_lists[root.index][root.next];
root.next += 1;
}
else root.element = INT_MAX; // problem is here
heap[0] = root;
make_heap(heap.begin(), heap.end());
}
}
My output is generally one of the inputted numbers and then 2147483647 (INT_MAX) for the rest of the output. I commented where/why this happens above, but overall I'm very confused on how to move within the for loop to the next element and continue going through the vectors to add more elements to the output.
Any help would be greatly appreciated!!

Is it ok if we remove [-Wreturn-local-addr] (warning: address of local variable returned) by using static keyword in c++?

I've a function :
int* sumCalc(int *p1, int *p2, int n1, int n2)
{
int sum[100] = {0};// = new int[n1+n2];
for(int i = 0; i < n1+n2; ++i)
{
sum[i] = p1[i] + p2[i];
}
return sum;
}
I'm calling this function from main() by writing :
int *sum = sumCalc(p1, p2, n1, n2);
So here I'm gonna get Warning.
To remove warning I changed my int array sum[100] as static and then I'm returning sum.
int* sumCalc(int *p1, int *p2, int n1, int n2)
{
static int sum[100] = {0};// = new int[n1+n2];
for(int i = 0; i < n1+n2; ++i)
{
sum[i] = p1[i] + p2[i];
}
return sum;
}
So is it a good practice to make the local variable static?
And if I to take the memory for array sum[100] from the heap then also I think this error would not be there. But can you tell how use new operator here and initialize all elements of array to zero?
The trouble is that in the first version, the variable is allocated off of the stack and not the heap. That means when the function returns, the sum variable disappears, and what you get is a random leftover address that points nowhere.
Yes, declaring the variable as static will make the warning disappear, but it is poor practice. What that tells the compiler is that there is only ever one copy of the sum variable, no matter how many times that the function is called. That means if you call the function again, the array will have the same contents.
int array1[3] = {1, 2, 3};
int array2[3] = {2, 3, 4};
int array3[2] = {5, 6};
int array4[2] = {7, 8};
int* returned = sumCalc(array1, array2, 3, 3);
int* gotcha = sumCalc(array3, array4, 2, 2); //Now returned is the same array as gotcha!
This can cause confusion because if you were expecting returned and gotcha to be different, you're in for a surprise. They will both be pointed to {12, 14}.
To allocate off of the heap, you have to use the new operator. You can find a number of ways to initialize the array in this question.
Edit: P.S. - Don't forget to delete the pointer allocated with new at the end of the program.
The keyword static when used in block scope would make
the sum behave like a function variable
it will be shared between different invocations of the functions
The above may not be desirable.
A work around would be
Defining int sum[100] = {0}; inside main
Passing a pointer to the same by modifying the sumCalc signature to something like
void sumCalc(int (*ptr)[100),int *p1, int *p2, int n1, int n2)
// Note the return type is void
and call it like
sumCalc(&sum,p1, p2, n1, n2);
And the loop inside the sum would be :
for(int i = 0; i < n1+n2; ++i)
{
(*ptr)[i] = p1[i] + p2[i];
}

Merge sort with a pointer to an array

I am trying to make a merge sort algorithm with the stl library but am having some issues. Below is the code I am using
template <typename Item, typename SizeType>
void merge_sort(Item array[], SizeType size){
size_t n1; //Size of the first subarray
size_t n2; //Size of the second subarray
if(size > 1){
//Compute the size of the subarrays
n1 = size/2;
n2 = size - n1;
//create the temp array.
int* n1Temp = new int[n1];
int* n2Temp = new int[n2];
int i;
for(i = 0; i < n1; i++)
n1Temp[i] = array[i];
for(i = 0; i < n2; i++)
n2Temp[i] = array[i + n1];
//recursive calls
merge_sort(n1Temp, n1);//sort from array[0] through array[n1 - 1]
merge_sort(n2Temp, n2);//sort from array[n1] to the end
//Merge the two sorted halves.
vector<int> v(array, array + size);
merge(n1Temp, n1Temp + n1, n2Temp, n2Temp + n2, v.begin());
copy(v.begin(), v.end(), array);//copy the vector back to the array
delete[] n1Temp;
delete[] n2Temp;
}
}
The code sorts fine but the problem is that it acts like a O(n^2) algorithm instead of O(n \log n), which is due to the creation of the vector in each merge sort call (I think). I tried removing the vector and just using an array in the merge function which can be seen below
//Merge the two sorted halves.
int* finalArray = new int[n1 + n2];
merge(n1Temp, n1Temp + n1, n2Temp, n2Temp + n2, begin(finalArray));
array = finalArray;
But this gets me nothing but errors. Is there any thing I can do to salvage my merge sort algorithm?
As both Vaughn and user93353 pointed out, you should be able to merge directly into the target array at each merge-point. But you can still use std::vector<> to make this significantly easier on yourself.
Also, your temp arrays are of direct type 'int', and I'm fairly sure that was intended to be the type of the template parameter Item. I'm not sure what the SizeType parameter is for, but I left it in case you had special ideas for it. Whatever it is, it better be compatible with size_t :
template <typename Item, typename SizeType>
void merge_sort(Item array[], SizeType size)
{
if(size > 1)
{
//Compute the size of the subarrays
size_t n1 = size/2;
//create the temp array
std::vector<Item> n1Temp(array, array+n1);
std::vector<Item> n2Temp(array+n1, array+size);
//recursive calls
merge_sort(&n1Temp[0], n1); //sort array[0] through array[n1-1]
merge_sort(&n2Temp[0], size-n1); //sort array[n1] through array[size-1]
// merge the sorted halves
std::merge(n1Temp.begin(), n1Temp.end(),
n2Temp.begin(), n2Temp.end(), array);
}
}
The above technique splits the sub-sequences top-down via copy, then merges in-place the split-copies into the original array. You can reduce this algorithm by one sublist allocation time (but no less space) by doing the splits on the original array, then merging into temp-space and copying after, which i think you were trying to do in the first place:
template <typename Item>
void merge_sort(Item ar[], size_t n)
{
if (n > 1)
{
// Compute the size of the subarrays
size_t n1 = n/2;
// invoke recursion on the submerges
merge_sort(ar, n1); //sort array[0] through array[n1-1]
merge_sort(ar+n1, n-n1); //sort array[n1] through array[size-1]
// create merge-buffer
std::vector<Item> mrg;
std::merge(ar, ar+n1, ar+n1, ar+n, back_inserter(mrg));
std::copy(mrg.begin(), mrg.end(), ar);
}
}
General Iterator-Based Solution
For a general solution that allows even more flexibility you can define your merge-sort based on iterators rather than Item pointers. It gets a little more hairy, but the benefits are very std-lib-ish.
template <typename Iterator>
void merge_sort(Iterator first, Iterator last)
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
difference_type n = std::distance(first, last)/2;
if (n == 0)
return;
// invoke recursion on the submerges
merge_sort(first, first + n);
merge_sort(first + n, last);
// create merge-buffer
std::vector<value_type> mrg(std::distance(first, last));
std::merge(first, first+n, first+n, last, mrg.begin());
std::copy(mrg.begin(), mrg.end(), first);
}
Finally, if you find yourself sorting a ton of fixed-length C-arrays you may find the following helpful (it uses the general-iterator solution above):
// front-loader for C arrays
template<typename Item, size_t N>
void merge_sort(Item (&ar)[N])
{
merge_sort(std::begin(ar), std::end(ar));
}
It make the following code rather convenient:
int arr[1024];
... fill arr ...
merge_sort(arr);

Pointer and memory allocation for the pointee

I have been struggling with pointer and memory allocation in c for a while.
Here's my implementation for the max subarray problem. It seems to work fine (maybe have bugs). But I have a question about the memory storage for tuple struct object. As you can see, tuple is declared in the global storage. Later in the findMaxSubArray() function, three pointers to Tuple struct are declared. My question is we didn't declare Tuple struct object instances that the pointers (left, right, cross) are addressing how come the pointer dereferences (i.e., left->sum, etc) work. Does the GNU c compiler automatically allocate storage for them? (I don't understand x86 assembly code) Can someone please explain what's going on here? Much appreciated.
#include <iostream>
using namespace std;
#define NEGINFINITY -2 << 31
typedef struct {
int lowPosition;
int highPosition;
int sum;
} Tuple;
Tuple tuple;
Tuple* findMaxCrossingSubArray(int a[], int low, int mid, int high) {
int leftSum, rightSum;
int leftMax, rightMax;
int sum;
leftSum = rightSum = NEGINFINITY;
sum = 0;
for (int i = mid; i >= low; --i) {
sum += a[i];
if (sum > leftSum) {
leftSum = sum;
leftMax = i;
}
}
sum = 0;
for (int j = mid + 1; j <= high; ++j) {
sum += a[j];
if (sum > rightSum) {
rightSum = sum;
rightMax = j;
}
}
tuple.lowPosition = leftMax;
tuple.highPosition = rightMax;
tuple.sum = leftSum + rightSum;
return &tuple;
}
Tuple* findMaxSubArray(int* array, int low, int high) {
Tuple *left, *right, *cross;
if (high == low) {
// base case
tuple.lowPosition = low;
tuple.highPosition = high;
tuple.sum = array[low];
return &tuple;
}
else {
int mid = (low + high) / 2;
left = findMaxSubArray(array, low, mid);
right = findMaxSubArray(array, mid + 1, high);
cross = findMaxCrossingSubArray(array, low, mid, high);
if (left->sum > right->sum && left->sum > cross->sum)
return left;
else if (right->sum > left->sum && right->sum > cross->sum)
return right;
else
return cross;
}
}
int main() {
Tuple *result;
int data[] = {1, -2, 3, 10, -4, 7, 2, -5};
result = findMaxSubArray(data, 0, 7);
for (int i = 0; i < 8; ++i)
cout << data[i] << " ";
cout << endl;
cout << "The sum of max subarray is " << result->sum
<< " Starting at index " << result->lowPosition
<< " ending at index " << result->highPosition << endl;
}
The global variable tuple is the only actual Tuple in this program. Memory for global variables is managed by the compiler.
In main, Tuple *result is just a pointer which, when you declared it, contains a random number (whatever happened to previously be in the space it now occupies) and thus result points to garbage (not a valid Tuple object).
Then you assign the result of findMaxSubArray to tuple. Since findMaxSubArray returns &tuple (in one way or another) which is a global variable, result points to the global variable tuple. So when you do result->sum, it's the same as doing tuple.sum.
In findMaxSubArray, the line Tuple *left, *right, *cross; declares three pointers to Tuples which contain a garbage value. In one branch of the if you don't use them and just return &tuple, the address of the global variable tuple. In the other branch, you set left, right, and cross to either findMaxCrossingSubArray or findMaxSubArray, which both return &tuple one way or the other.
I do suggest reading a book on C++ and forgetting everything you know about C while using C++ (but remember it all again when you program C again). They are not the same language. This code is riddled with things you learned from your C training (such as #define and typedef struct ... Tuple) for which C++ offers better facilities.
The only Tuple ever actually allocated is the tuple at global scope. All the pointers to Tuple, e.g. Tuple* left just point to that global storage. So for example in:
left = findMaxSubArray(array, low, mid);
right = findMaxSubArray(array, mid + 1, high);
You will find that left and right both point to the same address and hence have the same pointed to values.
Without working out the detail, and noting that this is C++, not C, you can probably just change the Tuple* return types to Tuple return by value and work with automatic (stack) storage.
The code becomes something like:
Tuple findMaxSubArray(int* array, int low, int high)
{
Tuple left, right, cross;
// blah blah
if (something)
return left;
else
return right;
}
All of your pointers (left, right, and cross) will always point to same memory location of &tuple. If you want different tuples you need to use malloc to create different Tuple strucks on the heap.