As I highlight in the following code, passing a pointer to a pointer "**" or passing a pointer "*" to LinkedListElement depends on what the function is to do. Any function is potentially to modify the argument head, a pointer to a pointer to LinkedListElement has to be passed, because the modification has to be made into the argument passed into the function. Otherwise a pointer to LinkedListElement should do the job.
// C Implementation of Linked List
//********************************************************************************
// LinkedListElement.h
#ifndef LINKED_LIST_ELEMENT_H
#define LINKED_LIST_ELEMENT_H
#pragma once
template <typename T>
struct LinkedListElement {
T data;
LinkedListElement<T>* next = nullptr;
LinkedListElement()
{}
LinkedListElement(const T& t) : data(t)
{}
~LinkedListElement()
{}
};
#endif
// LinkedListAlgo.h
#ifndef LINKED_LIST_ALGO_H
#define LINKED_LIST_ALGO_H
#pragma once
#include "LinkedListElement.h"
template<typename T>
void LL_PushFront(LinkedListElement<T>** head, const T& data)
{
if (*head == nullptr) {
*head = new LinkedListElement<T>(data);
}
else {
LinkedListElement<T>* curHead = *head;
*head = new LinkedListElement<T>(data);
(*head)->next = curHead;
}
}
template<typename T>
void LL_PushBack(LinkedListElement<T>** head, const T& data)
{
if (*head == nullptr) {
*head = new LinkedListElement<T>(data);
}
else {
LinkedListElement<T>* curHead = *head;
while (curHead->next != nullptr) {
curHead = curHead->next;
}
curHead->next = new LinkedListElement<T>(data);
}
}
template<typename T>
void LL_PopFront(LinkedListElement<T>** head)
{
if (head == nullptr || *head == nullptr) {
return;
}
LinkedListElement<T>* temp = *head;
*head = (*head)->next;
delete temp;
}
template<typename T>
void LL_PopBack(LinkedListElement<T>** head)
{
if (head == nullptr || *head == nullptr) {
return;
}
LinkedListElement<T>* prev = *head;
LinkedListElement<T>* curHead = *head;
while (curHead->next != nullptr) {
prev = curHead;
curHead = curHead->next;
}
prev->next = nullptr;
delete curHead;
}
template<typename T>
bool LL_Insert(LinkedListElement<T>** head, size_t pos, const T& data)
{
if (pos == 0) {
LL_PushFront(head, data);
return true;
}
LinkedListElement<T>* curHead = *head;
while (--pos > 0) {
curHead = curHead->next;
if (curHead == nullptr) {
return false;
}
}
LinkedListElement<T>* next = curHead->next;
curHead->next = new LinkedListElement<T>(data);
curHead->next->next = next;
return true;
}
template<typename T>
bool LL_Insert(LinkedListElement<T>** head, const LinkedListElement<T>* pos_node, const T& data)
{
if (head == nullptr || *head == nullptr || pos_node == nullptr) {
return false;
}
if (*head == pos_node) {
LL_PushFront(head, data);
return true;
}
LinkedListElement<T>* prev = nullptr;
LinkedListElement<T>* curHead = *head;
while (curHead != pos_node) {
prev = curHead;
curHead = curHead->next;
if (curHead == nullptr) {
return false;
}
}
prev->next = new LinkedListElement<T>(data);
prev->next->next = curHead;
return true;
}
template<typename T>
bool LL_Erase(LinkedListElement<T>** head, size_t pos)
{
if (head == nullptr || *head == nullptr) {
return false;
}
if (pos == 0) {
LL_PopFront(head);
return true;
}
LinkedListElement<T>* prev = *head;
LinkedListElement<T>* curHead = *head;
while (--pos > 0) {
prev = curHead;
curHead = curHead->next;
if (curHead == nullptr) {
return false;
}
}
prev->next = curHead->next;
delete curHead;
return true;
}
template<typename T>
bool LL_Erase(LinkedListElement<T>** head, const LinkedListElement<T>* pos_node)
{
if (head == nullptr || *head == nullptr || pos_node == nullptr) {
return false;
}
if (*head == pos_node) {
LL_PopFront(head);
return true;
}
LinkedListElement<T>* prev = nullptr;
LinkedListElement<T>* curHead = *head;
while (curHead != pos_node) {
prev = curHead;
curHead = curHead->next;
if (curHead == nullptr) {
return false;
}
}
prev->next = curHead->next;
delete curHead;
return true;
}
template<typename T>
bool LL_GetNth(LinkedListElement<T>* head, size_t pos, T& data)
{
if (head == nullptr) {
return false;
}
while (pos > 0) {
head = head->next;
if (head == nullptr) {
return false;
}
--pos;
}
data = head->data;
return true;
}
template<typename T>
LinkedListElement<T>* LL_GetNth(LinkedListElement<T>* head, size_t pos)
{
if (head == nullptr) {
return nullptr;
}
while (pos > 0) {
head = head->next;
if (head == nullptr) {
return nullptr;
}
--pos;
}
return head;
}
template<typename T>
size_t LL_GetSize(LinkedListElement<T>* head)
{
size_t size = 0;
while (head != nullptr) {
head = head->next;
++size;
}
return size;
}
template<typename T>
void LL_Reverse(LinkedListElement<T>** head)
{
// return if has less than 2 nodes
if (head == nullptr || *head == nullptr || (*head)->next == nullptr) {
return;
}
LinkedListElement<T>* cur = *head;
LinkedListElement<T>* next = nullptr;
LinkedListElement<T>* curHead = nullptr;
while (cur != nullptr) {
next = cur->next;
cur->next = curHead;
curHead = cur;
cur = next;
}
*head = curHead;
}
template<typename T>
void LL_Delete(LinkedListElement<T>** head)
{
if (head == nullptr || *head == nullptr) {
return;
}
LinkedListElement<T>* curHead = *head;
LinkedListElement<T>* temp = nullptr;
while (curHead != nullptr) {
temp = curHead;
curHead = curHead->next;
delete temp;
}
*head = nullptr;
}
/*
* return -1, if not found
* 0 - size-1, if found the very first
*/
template<typename T>
ptrdiff_t LL_Find(LinkedListElement<T>* head, const T& val)
{
if (head == nullptr) {
return -1;
}
ptrdiff_t pos = 0;
while (head != nullptr) {
if (head->data == val) {
return pos;
}
head = head->next;
++pos;
}
return -1;
}
template<typename T>
ptrdiff_t LL_Find(LinkedListElement<T>* head, size_t pos, const T& val)
{
if (head == nullptr) {
return -1;
}
while (pos > 0) {
head = head->next;
if (head == nullptr) {
return -1;
}
--pos;
}
return LL_Find(head, val);
}
#endif
// test.cpp
void TestLinkedListAlgo()
{
LinkedListElement<int>* head = nullptr;
// construct list: 20, 12, 10, 9, 9, 8, 7, 15
LL_PushFront(&head, 9);
LL_PushFront(&head, 10);
LL_PushFront(&head, 12);
LL_PushBack(&head, 9);
LL_PushBack(&head, 8);
LL_PushBack(&head, 7);
LL_PushBack(&head, 15);
LL_PushFront(&head, 20);
assert(LL_GetSize(head) == 8);
int val;
assert(LL_GetNth(head, 0, val) == true);
assert(val == 20);
assert(LL_GetNth(head, 1, val) == true);
assert(val == 12);
assert(LL_GetNth(head, 2, val) == true);
assert(val == 10);
assert(LL_GetNth(head, 3, val) == true);
assert(val == 9);
assert(LL_GetNth(head, 4, val) == true);
assert(val == 9);
assert(LL_GetNth(head, 5, val) == true);
assert(val == 8);
assert(LL_GetNth(head, 6, val) == true);
assert(val == 7);
assert(LL_GetNth(head, 7, val) == true);
assert(val == 15);
assert(LL_GetNth(head, 8, val) == false);
LL_PopFront(&head);
assert(LL_GetSize(head) == 7); // 12, 10, 9, 9, 8, 7, 15
LL_PopBack(&head);
assert(LL_GetSize(head) == 6); // 12, 10, 9, 9, 8, 7
LL_Delete(&head);
// constuct list: 18, 25, 30, 11, 10, 9, 5, 20
LL_PushBack(&head, 10);
LL_PushBack(&head, 9);
LL_PushBack(&head, 5);
LL_PushBack(&head, 20);
LL_PushFront(&head, 11);
LL_PushFront(&head, 30);
LL_PushFront(&head, 25);
LL_PushFront(&head, 18);
assert(LL_GetSize(head) == 8);
assert(LL_Insert(&head, 0, 40) == true); // 40, 18, 25, 30, 11, 10, 9, 5, 20
assert(LL_GetSize(head) == 9);
assert(LL_GetNth(head, 0, val) == true);
assert(val = 40);
assert(LL_Insert(&head, 10, 50) == false);
assert(LL_GetSize(head) == 9);
assert(LL_Insert(&head, 9, 50) == true); // 40, 18, 25, 30, 11, 10, 9, 5, 20, 50
assert(LL_GetSize(head) == 10);
assert(LL_GetNth(head, 9, val) == true);
assert(val == 50);
assert(LL_Insert(&head, 3, 100) == true); // 40, 18, 25, 100, 30, 11, 10, 9, 5, 20, 50
assert(LL_GetSize(head) == 11);
assert(LL_GetNth(head, 3, val) == true);
assert(val == 100);
LinkedListElement<int>* elemPtr = LL_GetNth(head, 2); // index starts from 0
assert(elemPtr != nullptr);
assert(elemPtr->data == 25);
assert(LL_GetNth(head, 11) == nullptr);
elemPtr = LL_GetNth(head, 9);
assert(elemPtr != nullptr);
assert(elemPtr->data == 20);
assert(LL_Insert(&head, elemPtr, 70) == true); // 40, 18, 25, 100, 30, 11, 10, 9, 5, 70, 20, 50
assert(LL_GetSize(head) == 12);
elemPtr = LL_GetNth(head, 9);
assert(elemPtr != nullptr);
assert(elemPtr->data == 70);
assert(LL_GetNth(head, 3, val) == true);
assert(val == 100);
assert(LL_GetNth(head, 12, val) == false);
assert(LL_GetSize(head) == 12);
assert(LL_Erase(&head, 0) == true); // 18, 25, 100, 30, 11, 10, 9, 5, 70, 20, 50
assert(LL_GetSize(head) == 11);
elemPtr = LL_GetNth(head, 0);
assert(elemPtr != nullptr);
assert(elemPtr->data == 18);
elemPtr = LL_GetNth(head, 10);
assert(elemPtr != nullptr);
assert(elemPtr->data == 50);
assert(LL_Erase(&head, elemPtr)); // 18, 25, 100, 30, 11, 10, 9, 5, 70, 20
assert(LL_GetSize(head) == 10);
assert(LL_GetNth(head, 10, val) == false);
assert(LL_GetNth(head, 9, val) == true);
assert(val == 20);
LL_PopFront(&head); // 25, 100, 30, 11, 10, 9, 5, 70, 20
assert(LL_GetSize(head) == 9);
elemPtr = LL_GetNth(head, 0);
assert(elemPtr != nullptr);
assert(elemPtr->data == 25);
LL_PopBack(&head); // 25, 100, 30, 11, 10, 9, 5, 70
assert(LL_GetSize(head) == 8);
assert(LL_GetNth(head, 8, val) == false);
assert(LL_GetNth(head, 7, val) == true);
assert(val == 70);
LL_Reverse(&head); // 70, 5, 9, 10, 11, 30, 100, 25
assert(LL_GetSize(head) == 8);
assert(LL_GetNth(head, 0, val) == true);
assert(val == 70);
assert(LL_GetNth(head, 1, val) == true);
assert(val == 5);
assert(LL_GetNth(head, 2, val) == true);
assert(val == 9);
assert(LL_GetNth(head, 3, val) == true);
assert(val == 10);
assert(LL_GetNth(head, 4, val) == true);
assert(val == 11);
assert(LL_GetNth(head, 5, val) == true);
assert(val == 30);
assert(LL_GetNth(head, 6, val) == true);
assert(val == 100);
assert(LL_GetNth(head, 7, val) == true);
assert(val == 25);
assert(LL_Insert(&head, 2, 10) == true); // 70, 5, 10, 9, 10, 11, 30, 100, 25
ptrdiff_t pos = LL_Find(head, 70);
assert(pos == 0);
pos = LL_Find(head, 25);
assert(pos == 8);
pos = LL_Find(head, 30);
assert(pos == 6);
pos = LL_Find(head, 10);
assert(pos == 2);
pos = LL_Find(head, 2, 10);
assert(pos == 0);
pos = LL_Find(head, 3, 10);
assert(pos == 1);
pos = LL_Find(head, 50);
assert(pos == -1);
LL_Delete(&head);
assert(head == nullptr);
assert(LL_GetSize(head) == 0);
}
Bibliography:
[1] http://cslibrary.stanford.edu/105/LinkedListProblems.pdf
[2] Glenn W. Rowe, Data Structure & Algorithm C++, Prentice Hall, 1996
No comments:
Post a Comment