opprenskning

This commit is contained in:
Trygve 2024-03-12 20:52:05 +01:00
parent 56cdc9248b
commit 45e01074bb
7 changed files with 70 additions and 71 deletions

View File

@ -2,8 +2,8 @@
#define DOUBLY_LINKED_LIST_H #define DOUBLY_LINKED_LIST_H
#include <cassert> #include <cassert>
#include <cstddef>
#include "queue.h" #include "queue.h"
#include "sequence.h"
namespace seq namespace seq
{ {

View File

@ -1,6 +1,8 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <iostream>
#include "queue.h"
#include "dynamic-array.h" #include "dynamic-array.h"
using namespace seq; using namespace seq;
@ -14,7 +16,6 @@ void DynamicArray::clear()
this->capacity = 0; this->capacity = 0;
} }
// insert an item at index i
void DynamicArray::enqueue(int value) void DynamicArray::enqueue(int value)
{ {
int i = this->logical_size; int i = this->logical_size;
@ -40,7 +41,7 @@ void DynamicArray::enqueue(int value)
// copy all of temp_storage into values[i+1] to values[logical_size] // 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]); std::copy(temp_storage, temp_storage + shifted_elements, &this->values[i+1]);
delete temp_storage; delete[] temp_storage;
} }
// now we can write the inserted item into values[i] // now we can write the inserted item into values[i]
@ -48,29 +49,35 @@ void DynamicArray::enqueue(int value)
this->values[i] = value; this->values[i] = value;
} }
// remove the item at index i
int DynamicArray::dequeue() int DynamicArray::dequeue()
{ {
int i = 0;
// shift all elements from index i+1 onward one to the left if (this->size() == 0) {
// we use a temporary storage and copy() from <algorithm> to do this efficiently return 0;
size_t shifted_elements = this->logical_size - i - 1;
if(shifted_elements > 0)
{
int* temp_storage = new int[shifted_elements]();
// copy values[i+1] to values[logical_size-1] into temp_storage
std::copy(this->values + i+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;
} }
this->logical_size--; // with this, we are done with the task int i = 0;
// Save the first element wich we want to return:
int outgoing = this->values[0];
// now let us see whether we have deleted so many items that we should resize to save memory // shift all elements from onward one to the left
if(this->capacity/2 >= this->logical_size) this->resize(this->capacity/2); 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, // allocate static array with "new_capacity" elements,

View File

@ -1,5 +1,4 @@
#include "queue.h" #include "queue.h"
#include "sequence.h"
namespace seq namespace seq
{ {

View File

@ -1,6 +1,7 @@
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <queue>
#include "dynamic-array.h" #include "dynamic-array.h"
#include "queue.h" #include "queue.h"
@ -12,11 +13,19 @@ namespace
/* /*
* run a simple test * run a simple test
*/ */
void test_sequence(seq::Queue* sqn, int n, int m, std::ostream* os) void test_queue(seq::Queue* sqn, int n, int m, std::ostream* os)
{ {
assert((m > 0) && (n > m)); assert((m > 0) && (n > m));
if(os) *os << "Enqueue even numbers from 0 to " << 2*(n-1) << ".\n"; 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->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();
} }
/* /*
@ -24,16 +33,38 @@ namespace
*/ */
float test_with_time_measurement(seq::Queue* sqn, int iterations) float test_with_time_measurement(seq::Queue* sqn, int iterations)
{ {
int sequence_length = 200001; int queue_length = 20001;
int deletions = 10; int deletions = 10;
test_sequence(sqn, sequence_length, deletions, &std::cout); test_queue(sqn, queue_length, deletions, &std::cout);
int log_entries = 10; int log_entries = 10;
std::cout << "\nNow repeat the above " << iterations << " times:\n"; std::cout << "\nNow repeat the above " << iterations << " times:\n";
auto t0 = std::chrono::high_resolution_clock::now(); auto t0 = std::chrono::high_resolution_clock::now();
for(int i = 0; i < iterations; i++) for(int i = 0; i < iterations; i++)
{ {
test_sequence(sqn, sequence_length, deletions, nullptr); 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) if((i+1) % (iterations/log_entries) == 0)
{ {
std::cout << "\t" << i+1 << "\n"; std::cout << "\t" << i+1 << "\n";
@ -61,7 +92,12 @@ int main()
seq::DoublyLinkedList dll; seq::DoublyLinkedList dll;
float dll_time = test_with_time_measurement(&dll, iterations); 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 << "\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 singly linked list:\t" << sll_time << " s\n";
std::cout << "Runtime for doubly linked list:\t" << dll_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";
} }

View File

@ -1,42 +0,0 @@
#ifndef SEQUENCE_H
#define SEQUENCE_H
#include <iostream>
namespace seq
{
class Sequence
{
public:
virtual bool empty() const = 0; // test whether the sequence is empty
virtual size_t size() const = 0; // return the size (number of items in the sequence)
// it is the caller's responsibility to ensure that the sequence is not empty when calling front() or back()!
virtual int& front() = 0; // return a reference to the first item
virtual int& back() = 0; // return a reference to the final item
// return a reference to the item at position i of the sequence, counting from 0
// it is the caller's responsibility that the index is within range
virtual int& at(int i) = 0;
/*
* accepts an additional item into the sequence (front or back);
* the pushed item is passed by reference, but a copy of it is stored in the Sequence
* the Sequence takes ownership of the copy (but not of the original!)
*/
virtual void push(const int& pushed_item) = 0; // default push operation (front or back)
virtual void push_front(const int& pushed_item) = 0;
virtual void push_back(const int& pushed_item) = 0;
virtual void pop() = 0; // default pop operation (front or back)
virtual void pop_front() = 0; // remove the first element
virtual void pop_back() = 0; // remove the last element
virtual void clear() = 0; // remove all the items from the sequence
// it is the caller's responsibility that the index is within range
virtual void insert_at(int i, const int& inserted_item) = 0; // insert an item at index i
virtual void erase_at(int i) = 0; // remove the item at index i
};
}
#endif

View File

@ -1,5 +1,5 @@
#include <cstddef>
#include "singly-linked-list.h" #include "singly-linked-list.h"
#include <algorithm>
using namespace seq; using namespace seq;

View File

@ -2,7 +2,6 @@
#define SINGLY_LINKED_LIST_H #define SINGLY_LINKED_LIST_H
#include <cassert> #include <cassert>
#include "sequence.h"
#include "queue.h" #include "queue.h"
namespace seq namespace seq
@ -36,7 +35,7 @@ namespace seq
bool empty() const { return (this->head == nullptr); } // test whether the singly linked list is empty 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) size_t size() const; // return the size (number of items in the singly linked list)
void enqueue(int element); void enqueue(int value);
int dequeue(); int dequeue();
void clear() { while(!this->empty()) this->dequeue(); } // remove all the items from the list void clear() { while(!this->empty()) this->dequeue(); } // remove all the items from the list