rename
This commit is contained in:
21
lab_3/17_and_18/Makefile
Normal file
21
lab_3/17_and_18/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
binary = sequence-test
|
||||
folder = sequences-int
|
||||
objects = $(patsubst %.cpp,%.o,$(wildcard *.cpp))
|
||||
|
||||
run: $(binary)
|
||||
./$(binary)
|
||||
|
||||
$(binary): $(objects)
|
||||
g++ -g3 -o $@ $^
|
||||
|
||||
%.o: %.cpp
|
||||
g++ -g3 -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
||||
clear: clean
|
||||
rm -f *.zip $(binary)
|
||||
|
||||
zip: clean
|
||||
zip $(folder) Makefile *.cpp *.h
|
||||
40
lab_3/17_and_18/doubly-linked-list.cpp
Normal file
40
lab_3/17_and_18/doubly-linked-list.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "doubly-linked-list.h"
|
||||
|
||||
using namespace seq;
|
||||
|
||||
// return the size (number of items in the doubly linked list)
|
||||
size_t DoublyLinkedList::size() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for(DoublyLinkedListNode* n = this->head; n != nullptr; n = n->get_next()) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// add an item at the end of the list
|
||||
void DoublyLinkedList::enqueue(int value)
|
||||
{
|
||||
DoublyLinkedListNode* new_node = new DoublyLinkedListNode;
|
||||
new_node->set_item(value);
|
||||
|
||||
if(this->empty()) this->head = new_node;
|
||||
else
|
||||
{
|
||||
this->tail->set_next(new_node);
|
||||
new_node->set_prev(this->tail); /** attachment in the doubly linked list goes both ways **/
|
||||
}
|
||||
this->tail = new_node;
|
||||
}
|
||||
|
||||
// remove the head node and item
|
||||
int DoublyLinkedList::dequeue()
|
||||
{
|
||||
if(this->empty()) return 0; // nothing there to remove
|
||||
DoublyLinkedListNode* successor = this->head->get_next();
|
||||
|
||||
if(successor) successor->set_prev(nullptr); /** we must detach the previous head node from its successor **/
|
||||
int outgoing = this->head->item;
|
||||
delete this->head;
|
||||
this->head = successor; // successor of the previous head is the new head
|
||||
if(this->head == nullptr) this->tail = nullptr; // catch special case: the list is now empty
|
||||
return outgoing;
|
||||
}
|
||||
64
lab_3/17_and_18/doubly-linked-list.h
Normal file
64
lab_3/17_and_18/doubly-linked-list.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef DOUBLY_LINKED_LIST_H
|
||||
#define DOUBLY_LINKED_LIST_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include "queue.h"
|
||||
|
||||
namespace seq
|
||||
{
|
||||
class DoublyLinkedListNode
|
||||
{
|
||||
public:
|
||||
// return a reference to the stored item
|
||||
int& get_item() { return this->item; }
|
||||
|
||||
// return pointer to next node, or nullptr if this is the final node
|
||||
DoublyLinkedListNode* get_next() const { return this->next; }
|
||||
|
||||
// return pointer to previous node, or nullptr if this is the initial node
|
||||
DoublyLinkedListNode* get_prev() const { return this->prev; }
|
||||
|
||||
// overwrite the item stored in this node
|
||||
void set_item(int in_item) { this->item = in_item; }
|
||||
|
||||
private:
|
||||
int item = 0;
|
||||
DoublyLinkedListNode* next = nullptr;
|
||||
DoublyLinkedListNode* prev = nullptr;
|
||||
|
||||
// attach a node behind this node
|
||||
// if there was a node attached to this previously, it is NOT deleted!
|
||||
void set_next(DoublyLinkedListNode* in_next) { this->next = in_next; }
|
||||
|
||||
// attach a node before this node
|
||||
// if there was a node attached to this previously, it is NOT deleted!
|
||||
void set_prev(DoublyLinkedListNode* in_prev) { this->prev = in_prev; }
|
||||
|
||||
friend class DoublyLinkedList; // allow DoublyLinkedList to access private members
|
||||
};
|
||||
|
||||
class DoublyLinkedList: public Queue
|
||||
{
|
||||
public:
|
||||
bool empty() const { return (this->head == nullptr); } // test whether the doubly linked list is empty
|
||||
size_t size() const; // return the size (number of items in the doubly linked list)
|
||||
|
||||
void enqueue(int element);
|
||||
int dequeue();
|
||||
|
||||
// return pointer to the head/tail node
|
||||
DoublyLinkedListNode* begin() const { return this->head; }
|
||||
DoublyLinkedListNode* end() const { return this->tail; }
|
||||
|
||||
void clear() { while(!this->empty()) this->dequeue(); } // remove all the items from the list
|
||||
|
||||
~DoublyLinkedList() { this->clear(); }
|
||||
|
||||
private:
|
||||
DoublyLinkedListNode* head = nullptr;
|
||||
DoublyLinkedListNode* tail = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
102
lab_3/17_and_18/dynamic-array.cpp
Normal file
102
lab_3/17_and_18/dynamic-array.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "queue.h"
|
||||
#include "dynamic-array.h"
|
||||
|
||||
using namespace seq;
|
||||
|
||||
// remove all the items from the array
|
||||
void DynamicArray::clear()
|
||||
{
|
||||
if(this->values) delete this->values;
|
||||
this->values = nullptr;
|
||||
this->logical_size = 0;
|
||||
this->capacity = 0;
|
||||
}
|
||||
|
||||
void DynamicArray::enqueue(int value)
|
||||
{
|
||||
int i = this->logical_size;
|
||||
|
||||
// catch the case where capacity is exhausted and we need to allocate more memory
|
||||
if(this->logical_size == this->capacity)
|
||||
{
|
||||
size_t new_capacity = 2 * this->capacity;
|
||||
if(new_capacity == 0) new_capacity = 1;
|
||||
this->resize(new_capacity);
|
||||
}
|
||||
assert(this->capacity > this->logical_size);
|
||||
|
||||
// shift all elements from index i onward one to the right
|
||||
// we use a temporary storage and copy() from <algorithm> to do this efficiently
|
||||
size_t shifted_elements = this->logical_size - i;
|
||||
if(shifted_elements > 0)
|
||||
{
|
||||
int* temp_storage = new int[shifted_elements]();
|
||||
|
||||
// copy values[i] to values[i+shifted_elements-1] into temp_storage
|
||||
std::copy(this->values + i, this->values + i + shifted_elements, temp_storage);
|
||||
|
||||
// copy all of temp_storage into values[i+1] to values[logical_size]
|
||||
std::copy(temp_storage, temp_storage + shifted_elements, &this->values[i+1]);
|
||||
delete[] temp_storage;
|
||||
}
|
||||
|
||||
// now we can write the inserted item into values[i]
|
||||
this->logical_size++;
|
||||
this->values[i] = value;
|
||||
}
|
||||
|
||||
int DynamicArray::dequeue()
|
||||
{
|
||||
|
||||
if (this->size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
int i = 0;
|
||||
// Save the first element wich we want to return:
|
||||
int outgoing = this->values[0];
|
||||
|
||||
// shift all elements from onward one to the left
|
||||
size_t shifted_elements = this->logical_size - 1;
|
||||
|
||||
int* temp_storage = new int[shifted_elements]();
|
||||
|
||||
// copy values[i+1] to values[logical_size-1] into temp_storage
|
||||
std::copy(this->values + 1, this->values + this->logical_size, temp_storage);
|
||||
|
||||
// copy all of temp_storage into values[i] to values[logical_size-2]
|
||||
std::copy(temp_storage, temp_storage + shifted_elements, &this->values[i]);
|
||||
delete[] temp_storage;
|
||||
if (!this->empty()) {
|
||||
this->logical_size--; // with this, we are done with the task
|
||||
|
||||
// now let us see whether we have deleted so many items that we should resize to save memory
|
||||
if(this->capacity/2 >= this->logical_size) this->resize(this->capacity/2);
|
||||
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
|
||||
// allocate static array with "new_capacity" elements,
|
||||
// copy the contents there, and delete the previous static array
|
||||
void DynamicArray::resize(size_t new_capacity)
|
||||
{
|
||||
assert(new_capacity >= this->logical_size);
|
||||
int* allocated_memory = new int[new_capacity]();
|
||||
|
||||
if(this->values != nullptr)
|
||||
{
|
||||
// use <algorithm> library construct for efficient memory-level copying
|
||||
// take values[0] to values[logical-size-1] and copy it into allocated_memory
|
||||
std::copy(this->values, this->values + this->logical_size, allocated_memory);
|
||||
|
||||
delete this->values; // now we can delete the old storage
|
||||
}
|
||||
|
||||
// update class properties
|
||||
this->values = allocated_memory;
|
||||
this->capacity = new_capacity;
|
||||
}
|
||||
27
lab_3/17_and_18/dynamic-array.h
Normal file
27
lab_3/17_and_18/dynamic-array.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "queue.h"
|
||||
|
||||
namespace seq
|
||||
{
|
||||
class DynamicArray: public Queue
|
||||
{
|
||||
public:
|
||||
bool empty() const { return (this->logical_size == 0); } // test whether the array is empty
|
||||
size_t size() const { return this->logical_size; } // return the logical size (number of items in the array)
|
||||
|
||||
void enqueue(int element);
|
||||
int dequeue();
|
||||
|
||||
void clear(); // remove all the items from the array
|
||||
~DynamicArray() { this->clear(); }
|
||||
|
||||
private:
|
||||
// this is a static C/C++ array containing the actual data
|
||||
// it is owned by the dynamic array
|
||||
int* values = nullptr;
|
||||
|
||||
size_t logical_size = 0; // how many data items are we actually storing?
|
||||
size_t capacity = 0; // how much memory did we allocate?
|
||||
|
||||
void resize(size_t new_capacity); // shift to static array with increased/decreased capacity
|
||||
};
|
||||
}
|
||||
12
lab_3/17_and_18/queue.h
Normal file
12
lab_3/17_and_18/queue.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
namespace seq {
|
||||
class Queue {
|
||||
public:
|
||||
virtual void enqueue(int element) = 0;
|
||||
virtual int dequeue() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
103
lab_3/17_and_18/sequence-test.cpp
Normal file
103
lab_3/17_and_18/sequence-test.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
#include "dynamic-array.h"
|
||||
#include "queue.h"
|
||||
#include "singly-linked-list.h"
|
||||
#include "doubly-linked-list.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
/*
|
||||
* run a simple test
|
||||
*/
|
||||
void test_queue(seq::Queue* sqn, int n, int m, std::ostream* os)
|
||||
{
|
||||
assert((m > 0) && (n > m));
|
||||
if(os) *os << "Enqueue even numbers from 0 to " << 2*(n-1) << ".\n";
|
||||
for(int i = 0; i < n; i++) sqn->enqueue(2*i);
|
||||
for(int i = 0; i < n; i++) sqn->dequeue();
|
||||
}
|
||||
void test_queue(std::queue<int>* sqn, int n, int m, std::ostream* os)
|
||||
{
|
||||
assert((m > 0) && (n > m));
|
||||
if(os) *os << "Enqueue even numbers from 0 to " << 2*(n-1) << ".\n";
|
||||
for(int i = 0; i < n; i++) sqn->push(2*i);
|
||||
for(int i = 0; i < n; i++) sqn->pop();
|
||||
}
|
||||
|
||||
/*
|
||||
* return time measurement in units of seconds
|
||||
*/
|
||||
float test_with_time_measurement(seq::Queue* sqn, int iterations)
|
||||
{
|
||||
int queue_length = 20001;
|
||||
int deletions = 10;
|
||||
test_queue(sqn, queue_length, deletions, &std::cout);
|
||||
|
||||
int log_entries = 10;
|
||||
std::cout << "\nNow repeat the above " << iterations << " times:\n";
|
||||
auto t0 = std::chrono::high_resolution_clock::now();
|
||||
for(int i = 0; i < iterations; i++)
|
||||
{
|
||||
test_queue(sqn, queue_length, deletions, nullptr);
|
||||
if((i+1) % (iterations/log_entries) == 0)
|
||||
{
|
||||
std::cout << "\t" << i+1 << "\n";
|
||||
std::cout.flush(); // make sure that status output is shown without delay
|
||||
}
|
||||
}
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
return 1.0e-06 * std::chrono::duration_cast<std::chrono::microseconds>(t1-t0).count();
|
||||
}
|
||||
|
||||
float test_with_time_measurement(std::queue<int>* sqn, int iterations)
|
||||
{
|
||||
int queue_length = 20001;
|
||||
int deletions = 10;
|
||||
test_queue(sqn, queue_length, deletions, &std::cout);
|
||||
|
||||
int log_entries = 10;
|
||||
std::cout << "\nNow repeat the above " << iterations << " times:\n";
|
||||
auto t0 = std::chrono::high_resolution_clock::now();
|
||||
for(int i = 0; i < iterations; i++)
|
||||
{
|
||||
test_queue(sqn, queue_length, deletions, nullptr);
|
||||
if((i+1) % (iterations/log_entries) == 0)
|
||||
{
|
||||
std::cout << "\t" << i+1 << "\n";
|
||||
std::cout.flush(); // make sure that status output is shown without delay
|
||||
}
|
||||
}
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
return 1.0e-06 * std::chrono::duration_cast<std::chrono::microseconds>(t1-t0).count();
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int iterations = 200;
|
||||
|
||||
std::cout << "*** test with dynamic array ***\n";
|
||||
seq::DynamicArray dyna;
|
||||
float dyna_time = test_with_time_measurement(&dyna, iterations);
|
||||
|
||||
std::cout << "\n\n*** test with singly linked list ***\n";
|
||||
seq::SinglyLinkedList sll;
|
||||
float sll_time = test_with_time_measurement(&sll, iterations);
|
||||
|
||||
std::cout << "\n\n*** test with doubly linked list ***\n";
|
||||
seq::DoublyLinkedList dll;
|
||||
float dll_time = test_with_time_measurement(&dll, iterations);
|
||||
|
||||
std::cout << "\n\n*** test with std::queue ***\n";
|
||||
std::queue<int> queue;
|
||||
float queue_time = test_with_time_measurement(&queue, iterations);
|
||||
|
||||
std::cout << "\n\nRuntime for dynamic array:\t" << dyna_time << " s\n";
|
||||
std::cout << "Runtime for singly linked list:\t" << sll_time << " s\n";
|
||||
std::cout << "Runtime for doubly linked list:\t" << dll_time << " s\n";
|
||||
std::cout << "Runtime for std::queue:\t" << queue_time << " s\n";
|
||||
}
|
||||
33
lab_3/17_and_18/singly-linked-list.cpp
Normal file
33
lab_3/17_and_18/singly-linked-list.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <cstddef>
|
||||
#include "singly-linked-list.h"
|
||||
|
||||
using namespace seq;
|
||||
|
||||
// return the size (number of items in the singly linked list)
|
||||
size_t SinglyLinkedList::size() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for(SinglyLinkedListNode* n = this->head; n != nullptr; n = n->get_next()) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
void SinglyLinkedList::enqueue(int value)
|
||||
{
|
||||
SinglyLinkedListNode* new_node = new SinglyLinkedListNode;
|
||||
new_node->set_item(value);
|
||||
|
||||
if(this->empty()) this->head = new_node;
|
||||
else this->tail->set_next(new_node);
|
||||
this->tail = new_node;
|
||||
}
|
||||
|
||||
int SinglyLinkedList::dequeue()
|
||||
{
|
||||
if(this->empty()) return 0; // nothing there to remove
|
||||
SinglyLinkedListNode* successor = this->head->get_next();
|
||||
int outgoing = this->head->item;
|
||||
delete this->head;
|
||||
this->head = successor; // successor of the previous head is the new head
|
||||
if(this->head == nullptr) this->tail = nullptr; // catch special case: the list is now empty
|
||||
return outgoing;
|
||||
}
|
||||
50
lab_3/17_and_18/singly-linked-list.h
Normal file
50
lab_3/17_and_18/singly-linked-list.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef SINGLY_LINKED_LIST_H
|
||||
#define SINGLY_LINKED_LIST_H
|
||||
|
||||
#include <cassert>
|
||||
#include "queue.h"
|
||||
|
||||
namespace seq
|
||||
{
|
||||
class SinglyLinkedListNode
|
||||
{
|
||||
public:
|
||||
// return a reference to the stored item
|
||||
int& get_item() { return this->item; }
|
||||
|
||||
// return pointer to next node, or nullptr if this is the final node
|
||||
SinglyLinkedListNode* get_next() const { return this->next; }
|
||||
|
||||
// overwrite the item stored in this node
|
||||
void set_item(int in_item) { this->item = in_item; }
|
||||
|
||||
private:
|
||||
int item = 0;
|
||||
SinglyLinkedListNode* next = nullptr;
|
||||
|
||||
// attach a node to this node
|
||||
// if there was a node attached to this previously, it is NOT deleted!
|
||||
void set_next(SinglyLinkedListNode* in_next) { this->next = in_next; }
|
||||
|
||||
friend class SinglyLinkedList; // allow SinglyLinkedList to access private members
|
||||
};
|
||||
|
||||
class SinglyLinkedList: public Queue
|
||||
{
|
||||
public:
|
||||
bool empty() const { return (this->head == nullptr); } // test whether the singly linked list is empty
|
||||
size_t size() const; // return the size (number of items in the singly linked list)
|
||||
|
||||
void enqueue(int value);
|
||||
int dequeue();
|
||||
|
||||
void clear() { while(!this->empty()) this->dequeue(); } // remove all the items from the list
|
||||
~SinglyLinkedList() { this->clear(); }
|
||||
|
||||
private:
|
||||
SinglyLinkedListNode* head = nullptr;
|
||||
SinglyLinkedListNode* tail = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user