Okay, 0x00sec people! Now for insert(...)
. I expect this to be the last technical part of the Linked List subseries before a fairly significant code dump.
Algorithm Description
Our insertion function takes two parameters: T val
and const size_t& idx
.
-
T val
is a value of typeT
(remember, I liketemplate
s) to be inserted. -
const size_t& idx
is the index at which a newnode
is to be placed.
The function will return val
upon a successful run; otherwise, it will throw
an exception (to be explained later).
So, insert(...)
will traverse the list until it reaches the index idx
desired, or until the end of the List
is reached. If we never arrive at idx
, the exception (again, to be discussed later) gets throw
n.
Time Complexity: O(n)
.
Source Code
template <class T>
T List<T>::insert(T val, const size_t& idx) {
if (idx == 0 && root == nullptr) {
this->append(val);
return val;
}
node<T>* h = root;
size_t cnt = 0;
while(cnt < idx - 1 && h != nullptr) {
h = h->next;
cnt++;
}
if (cnt == idx - 1) {
if (h != nullptr) {
node<T>* new_node = new node<T>(val);
new_node->next = h->next;
h->next = new_node;
len++; // update length
return val;
}
}
// WATCH THIS LINE
throw std::out_of_range("ERROR: called insert() past the acceptable range of the current linked list");
}
Oh dear! That’s hella code. Let’s get to it…
First, we want to check if root
is nullptr
. If it is, and if we’re trying to insert at idx = 0
, we call a function append()
, which I have yet to reveal, that tacks on to the end. In this case, our insert(...)
ing is done, so we return right then and there.
The next two lines of the function should remind you of the delete(...)
function from last time (wait, you didn’t read that?).
In the while
loop we traverse the list (again, much like we did so in delete(...)
) until we reach idx - 1
or the end of the list. Note: I chose idx - 1
so that h
is the node
before. Thus, the new node
becomes h->next
.
The while
loop ended. Now we must check a few things:
- Are we at
idx - 1
; meaning, are we where we want to be (in the list)? - Did we hit the end of the list already?
First, I make sure that first condition is true. Inside that if
, though, I put a second if
, reading if (h != nullptr)
. This is because, if h
(which is some_list[ idx - 1 ]
) is a nullptr
, that means that we’ve come just short of the index idx
where we want to put a new node
. Note: We can’t just tack on a new node
at idx - 1
if h
is a nullptr
because then we wouldn’t be inserting at idx
, now would we?
Okay, but what if we pass both conditions? Now we’re inside the nested if
s.
- Construct a new
node<T>*
and setval
as itsdata
. - Set
new_node->next
toh->next
. In math-y English, this means "makesome_list[ idx ]
point tosome_list[ idx + 1]
". Ifh->next
is anullptr
, that won’t affect us, because anynode
's defaultnext
defaults tonullptr
, anyway! - Make
h->next = new_node
; ensure thatsome_list[ idx - 1 ]
points tosome_list[ idx ]
. We are trying to not lose anynode
s (because that’d be a memory leak, and good programmers don’t leak their memories). - Increment the length
len
of the list to account for this shiny newnode
we’ve justinsert(...)
ed! -
return val
, thereby ending our presence in the function before reaching that defaultthrow
.
Brief Explanation of the Default Exception
throw std::out_of_range("ERROR: there is no node at that index to delete!");
What does this mean? So, if we don’t reach the spot in the list where we wanted to insert(...)
a new node
, what do we do? Do we panic? Sort of. But it’s 2016! Let’s be civil about how we panic by using exception
s. This way, the caller of the function can accommodate for trying to insert(...)
past the bounds, or out_of_range
, of the list.
Conclusion
That’s insert(...)
for ya! I now challenge you to implement an insert
ion function that takes a linked list rather than one value to insert! Would you want to copy over all the values? What would you do?
That’s it for today,
oaktree
A microphone can be heard hitting the ground.