Linked List Exercises
Linked List Exercises
* @file LinkedListExercises.h
* University of Illinois CS 400, MOOC 2, Week 1: Linked List
* Spring 2019
* STUDENT STARTER FILE
*
* @author Eric Huber - University of Illinois staff
*
**/
/********************************************************************
Week 1: Linked List and Merge Sort Exercises
There are two exercises in this file. Please read the code comments
below and see the provided instructions PDF before you begin. The
other provided code files in the starter zip also contain important
comments and hints about how to approach this.
This is the only file you can edit for the sake of grading! You can
edit the other provided starter files for testing purposes, but the
autograder will assume that this is the only file that has been edited
by you, and the others will be replaced with the original intended
versions at grading time.
********************************************************************/
// Prevent the header from being included more than once per cpp file
#pragma once
// It's good to put system headers first, so that if your own libraries
// cause conflicts, the compiler will most likely identify the problem
// as being in your own source code files, where it arises later.
#include <iostream>
#include <string>
#include "LinkedList.h"
/********************************************************************
Exercise 1: insertOrdered
You can use "make test" followed by "./test" to check the correctness
of your implementation, and then you can use "./test [.bench]" to run
some interesting benchmarks on the speed of your code.
********************************************************************/
//std::cout<<"Element "<<newData<<std::endl;
/*
Empty list
Single Element List
Multi Element List
*/
Node* currentNodePtr = this->getHeadPtr();
while (currentNodePtr){
if (currentNodePtr->data <= newData){
std::cout<<"check 1"<<std::endl;
// For single element list, reached to the end of the list modify
the tail
if (!currentNodePtr->next){
tail_ = newNodePtr;
newNodePtr->prev = currentNodePtr;
currentNodePtr->next = newNodePtr;
size_++;
std::cout<<"check 2"<<std::endl;
return;
}
} else {
Node* previousToCurrentNodePtr = currentNodePtr->prev;
currentNodePtr = currentNodePtr->next;
}
return;
// -----------------------------------------------------------
// TODO: Your code here!
// -----------------------------------------------------------
// Please implement this function according to the description
// above and in the instructions PDF.
// Hints:
// Make your new node on the heap and then find where it needs to
// go in the list. A good way to do this is by considering special
// base cases first, then walk the list from front to back and find
// the earliest position where you should insert the new node.
// When you insert the node, make sure to update any and all pointers
// between it and adjacent nodes accordingly (next and prev pointers).
// You may also need to update the head_ and tail_ pointers in some
// cases. Also update the size_ variable of the list.
// More hints:
// Consider all the cases that can happen when you're trying to insert
// the new node. Is the list currently empty? Does the new node go
// at the beginning? Does it go somewhere in the middle? Does it go
// at the end? Remember that this is a doubly-linked list, so there
// may be prev and next pointers to adjust on both sides of the node
// that you insert.
/********************************************************************
Exercise 2: Linear-time Merge
This LinkedList member function is intended to perform the classic
"merge" operation from the mergesort algorithm. It combines two sorted
lists into a single sorted list. This algorithm is intended to run
in linear time (that is, O(n) where n is the total number of elements
in the input lists), so it is not appropriate to simply concatenate
the two lists and then apply a sorting algorithm. Instead, the merge
algorithm relies on the fact that the two input lists are already sorted
separately in order to create the merged, sorted list in linear time.
One of the implied input lists is the "*this" LinkedList instance that
is calling the function, and the other input list is explicitly specified
as the function argument "other". The function does NOT change either
of the original lists directly, as the inputs are marked const.
Instead, this function makes a new list containing the merged result,
and it returns a copy of the new list. For example, one usage might
look like this (OUTSIDE of this function, where we are making the call):
LinkedList<int> leftList;
// [... Add some sorted contents to leftList here. ...]
LinkedList<int> rightList;
// [... Add some sorted contents to rightList here. ...]
LinkedList<int> mergedList = leftList.merge(rightList);
You may assume that the two input lists have already been sorted.
However, the lists may be empty, and they may contain repeated or
overlapping elements. The lists may also have different lengths.
For example, it's possible that these are the two input lists:
And the result of merging those two sorted lists will contain all
of the same elements, including the correct number of any duplicates,
in sorted order:
[1, 1, 2, 2, 3, 3, 5, 5, 5, 5, 6, 7]
1. Since both lists being merged are already sorted themselves, there
is a way to merge them together into a single sorted list in a single
traversal pass down the lists. This can run in O(n) time.
2. You SHOULD NOT call any sorting function in your merge function.
3. You SHOULD NOT call the insertOrdered function in merge. That would
result in a very slow running time. (The insertOrdered function was
part of the insertion sort exercise. It has nothing to do with merge
or merge sort.)
You can use "make test" followed by "./test" to check the correctness
of your implementation, and then you can use "./test [.bench]" to run
some interesting benchmarks on the speed of your code.
********************************************************************/
// We will also create an empty list called "merged" where we can build
// the final result we want. This is what we will return at the end of
// the function.
LinkedList<T> merged;
// -----------------------------------------------------------
// TODO: Your code here!
// -----------------------------------------------------------
// Please implement this function according to the description
// above and in the instructions PDF.
// Hints:
// 1. Assuming that the left and right lists are already sorted, remember
// that the smallest items are already available at the front. You can
// access them immediately.
// 2. Think of which item needs to be placed first in the merged list.
// Then think about what item should be placed second. You need to
// think carefully about which list to take from next after you take
// each single item.
// 3. You can do this while walking down the left and right lists exactly
// once. Do not loop over the lists multiple times. If you are doing
// that, your implementation is probably already running in O(n^2)
// time or worse, and not O(n).
// 4. Remember, DO NOT try to use insertOrdered here. That would be
// very slow.
// -----------------------------------------------------------
// We return the merged list by value here. It may be copied out of the
// function, but usually the compiler will optimize this to automatically
// create it directly in the correct memory space outside without copying.
// Don't worry about the speed of that right now. (By the way, did you
// notice that all of our nodes are created on the heap? The part of the
// list that we pass back is really small; it just contains two pointers
// and an int.)
return merged;
}