So I recently came across a data structure roughly like this:
template<class T>
struct Node {
size_t m_next;
size_t m_prev;
T m_key;
}
template<class T, size_t N>
struct DS {
Node<T> m_elements[N];
size_t m_head;
size_t m_tail;
}
I simplified a bit, just to keep this brief: I don't do error handling when DS gets too full. Normally N is large enough that this isn't a concern.
One note is T must have some way of representing "no value"; why this is needed can be seen below. (I'll refer to this value as TOMBSTONE below.)
The API for this data structure is roughly the same as for a linked list, but it performs much better because everything fits nicely in the cache.
The actual implementation is different from a linked list in that it doesn't need to allocate any new memory for new nodes. For example, pushing to the back of DS is roughly like this:
void DS::push_back(T t) {
size_t attempt = 0;
size_t i = hash(t, attempt++);
while (true) {
if (m_elements[i] == TOMBSTONE) {
m_elements[m_tail].m_next = i;
m_elements[i] = Node(N, m_tail, t);
m_tail = i;
break;
}
i = hash(t, attempt++);
}
}
where hash(T t, size_t attempt) finds places to try to insert new elements. (This is so there's nice spread, rather than clumping everything at the start.)
I hesitate to call this a linked list because of the vast performance and implementation differences from a normal linked list. I also want to point out that this question is not about when to use what data-structures, or if the above data-structure is good/fast/safe/whatever. This data-structure works quite well for us in the very specific situation we use it in.
Is there any name for this particular implementation/data-structure?
It is linked list. It's mentioned on Wikipedia as "Linked list using arrays of nodes"
It's a double-linked linked list, implemented with a C-style array.
Related
My preorder method don't work from main, but array elem has been formed rightly (I checked it with printing every step). All functions/methods used in definition work correctly. I think the problem occurs because of line "return elem;". Can anyone suggest any idea, it's too important.
T* TreeNode<T>::preorder()const
{
T* elem = new T[elCount(left)+elCount(right)+1];
elem[0] = data;
TreeNode<T>* curr = left;
Stack<TreeNode<T>*> st;
if (right) {
st.push(right);
}
int i = 1;
while (curr) {
elem[i++] = curr->getData();
//std::cout << elem[i - 1];
if (curr->getRight())
st.push(curr->getRight());
curr = curr->getLeft();
if (!curr)
{
curr = st.getTop();
st.pop();
} }
return elem;
}
It's a bit difficult to see exactly what you're trying to do as it wasn't specified, but it seems that you're trying to grab all the data from your binary tree. This GFG article does a really simple explanation and breakdown of how to transverse a binary tree. Obviously your nodes are more complicated, but the general logic is the same. I'd ask yourself as to whether the preorder() function really needs to be part of the tree node class and if a separate function wouldn't be a bit more useful. I'd also consider using a std::vector rather than the carray you're currently using. If you need the fixed size, std::array would probably also work better.
To show how you could possibly rewrite your code you can try something like
std::vector<int> vect;
template<class T>
void preorder(const TreeNode<T>& node, vector<T>& elem) {
if(!node.getData()) {
return;
}
elem.push(node.getData());
if(node.getLeft()) {
preorder(node.getLeft());
}
if(node.getRight()) {
preorder(node.getRight());
}
}
This isn't perfect as I wrote this off the top of my head, but it should provide an easy groundwork for traversing the binary tree and pulling out all the data. A little bit of recursion should make it a lot easier.
I am solving exercises for a C++ exam I have soon. Consider the following exercise:
A travel agency uses lists to manage its trips. For each trip the agency registers its point of departure, point of arrival, distance and time/duration
1) Define the necessary structures to represent a list of trips
2) Write a function that, given integer i returns the point of departure and point of arrival of the trip in position i
Defining the structure is easy:
struct list{
char departure[100];
char arrival[100];
double distance;
double time;
list* next = NULL;
};
My problem is the function. The actual work, to find the ith trip is easy. But how can I return the two char arrays/strings departure and arrival? If this were a question in my exam, I would have solved it like this:
typedef list* list_ptr;
list_ptr get_trip(list_ptr head, const int i){
if(i<0 || head==NULL){
return NULL;
}
for(int k = 0; k<i;k++){
head = head->next;
if(head==NULL){
return NULL;
}
}
return head;
}
I am returning a pointer to the list element. One then has to print departure and arrival. I could easily return just the departure or just the arrival by using a function with return type char*. How can I properly return 2 strings?
I know that there is ways doing this using std::tuple, but I cannot use this as we haven't had it in the lecture(we only had the really basic stuff, up to classes).
Am I right that returning both strings is not possible without using additional libraries?
Cheers
OK, to start with, your list type has some problems. Don't use char[] in C++ unless you really, really have to (note: if you think you have to, you're probably wrong). C++ provides a standard library that is wonderous in its applications (well, compared to C), and you should use it. In particular, I'm talking about std::string. You're probably OK using double for distance and duration, although a lack of units means that you're going to have a bad time.
Let's try this:
struct Trip {
std::string departure;
std::string arrival;
double distance_km;
double duration_hours;
};
Now you can either use std::vector, std::list, std::slist, or roll your own list. Let's assume the last.
class TripList {
public:
TripList() = default;
// Linear in i.
Trip& operator[](std::size_t i);
const Trip& operator[](std::size_t i) const;
void append_trip(Trip trip);
void remove_trip(std::size_t i);
private:
struct Node {
Trip t;
std::unique_ptr<Node> next;
};
std::unique_ptr<Node> head;
Node* tail = nullptr; // for efficient appending
};
I'll leave implementation of this to you. Note that list and trip are separate concepts, so we're writing separate types to handle them.
Now you can write a simple function:
std::pair<string, string> GetDepartureAndArrival(const TripList& list, std::size_t index) {
const auto& trip = list[index];
return {trip.departure, trip.arrival};
}
I'm trying to write a Interpreted programming language like Python, so i need a List class for storing 'address of' functions and variables. I'm implemented Stack class for implementing List class:
typedef unsigned int UIntegerP; //This type for storing addresses
#define Free 0x0
template <typename T> class Stack{
public:
unsigned long UsedBSize; // You can use that like End Of Stack (EOS)
Stack(void){
this->BSize = 0; this->UsedBSize = 0;
this->Buffer = new T;
}
~Stack(void){
delete this->Buffer;
}
inline void Push(T Variable){
if(this->UsedBSize == this->BSize){
this->BSize++;
} this->Buffer[this->UsedBSize] = Variable; this->UsedBSize++;
}
inline T Pop(bool IsProtected = false){
if(IsProtected){
return this->Buffer[this->UsedBSize];
}else{
this->UsedBSize--; T Element = this->Buffer[this->UsedBSize]; this->Buffer[this->UsedBSize] = Free;
return Element;
}
}
private:
T *Buffer;
unsigned long BSize;
};
And this is the class i want to implement:
class List{
private:
Stack<UIntegerP> *stack = new Stack<UIntegerP>; //A stack for storing variable addresses
public:
~List(void){
delete this->stack;
}
List(Stack<UIntegerP> Elements){
while(Elements.UsedBSize != 0){
this->stack->Push(Elements.Pop());
}
}
List(Stack<UIntegerP> *Elements){
while(Elements->UsedBSize != 0){
this->stack->Push(Elements->Pop());
}
}
UIntegerP Get(unsigned long Size); //Get Address with Index number
UIntegerP Set(unsigned long Size, UIntegerP Address); //Set Address with Index number
};
I will use this List class for implementing Python like dictionaries. UIntegerP type is required for Variable class. How i can implement this two functions?
Assuming your stack exposes only the Push and Pop functions, then you can't efficiently implement list with indexing on top of that.
If you're programming in normal C++ style, then the basic data structure would be a dynamic array or a linked list. You can then build a stack on top of those. But note that indexing in a linked list is going to be slow (linear time complexity).
If you're programming in a functional style, then the basic structure is "list", which is an immutable singly-linked list and it's effectively the same as immutable stack. But again, indexing with that is going to be slow.
Also note that your Stack is implemented incorrectly: you're allocating memory for a single T, but then you assume you can use that for an unlimited number of Ts. You either need to go the linked list route: allocate a new node for each item and connect the nodes with pointers; or you need to go the dynamic array route: allocate an array of a certain size and when it gets too small, reallocate it.
I'm practicing with some binary tree algorithms in C++ and trying to write as generic code as possible. In particular, I would like my functions (algorithms) be able to operate on any (to some extend, of course) tree-like data structures.
A tree node structure might be defined in different ways, like this, for instance:
struct binary_tree_node
{
int data;
struct binary_tree_node *left;
struct binary_tree_node *right;
};
Or like this:
struct binary_tree_node2
{
long key;
struct binary_tree_node2 *first_child;
struct binary_tree_node2 *second_child;
};
Or anyhow else, but pretty similar to that pattern.
So I would like my functions/algorithms be able to work with any of these or similar data structures.
For example, here is how I define one simple function:
template <typename TreeNode, typename DataType = typename TreeNode::data_type>
TreeNode*
binary_tree_new_node(DataType value = DataType(),
DataType TreeNode::* data = &TreeNode::data,
TreeNode* TreeNode::* left = &TreeNode::left,
TreeNode* TreeNode::* right = &TreeNode::right)
{
TreeNode *newnode = new TreeNode();
newnode->*data = value;
newnode->*left = nullptr;
newnode->*right = nullptr;
return newnode;
}
Thus, it is possible to use the function with any suitable tree-node type of your choice. If the data members have different names (not data, left and right), then one can call the function and pass the pointers to the corresponding data members. This way, the function does not depend on (or at least can adjust itself to) how the data members of the input type are named.
It worked pretty well so far, but as I implement more and more functions, I'm getting tired of these pointer-to-data-member parameters which I have to list as optional parameters of the functions. So is there any better way to handle this? Maybe some sort of traits? Or somehow else?
I would like to keep the requirements on the input type as few as possible. For example, the client program should not be forced to define anything more than just the tree-node type. It shall not also be forced to use/derive-from any provided types or templates. Of course, the client program might re-use some of the provided templates, like the one below, which I also define, but should not really be forced to.
template<typename T>
struct binary_tree_node
{
using data_type = T;
data_type data;
struct binary_tree_node *left;
struct binary_tree_node *right;
};
What are the available options here?
Does it make any sense at all? :)
Thanks in advance
The way the STL collection libraries work is that the author of the tree library would supply the node class so that all the user of the template needs to do is supply the data. The other option which you seem to be going for are intrusive data structures(that would be a good term to google for ideas). With those you have a couple of choices, the first is require the data members to be left, right, and data. Second require access functions with a specific name so the template can find them. Third require functors to be passed in as template parameters so you can use them to find the data you need. Personally I find the STL way the least messy, followed by the functors approach.
To make your algorithm as generic as possible I recommend using functors. Your binary_tree_new_node would look like
template<typename G, typename L, typename R, typename AT, typename AD, typename D>
auto binary_tree_new_node(
G generator,
L left,
R right,
AT assign_tree,
AD assign_data,
D data) ->decltype( generator() )
{
auto tree = generator();
auto& l = left(tree);
auto& r = right(tree);
assign_data(tree, data);
assign_tree(l, nullptr);
assign_tree(r, nullptr);
return tree;
}
For your binary_tree_node, the functors would look like:
// WARNING!!! Very dangerous code!!!
binary_tree_node* generator()
{
return new binary_tree_node;
}
binary_tree_node*& left(binary_tree_node* tree)
{
return tree->left;
}
binary_tree_node*& right(binary_tree_node* tree)
{
return tree->right;
}
void assign_data(binary_tree_node* node, int data)
{
node->data = data;
}
void assign_tree(binary_tree_node*& node, binary_tree_node* data)
{
node = data;
}
How can I create a list in C++? I need it to create a linked list. How would I go about doing that? Are there good tutorials or examples I could follow?
I take it that you know that C++ already has a linked list class, and you want to implement your own because you want to learn how to do it.
First, read Why do we use arrays instead of other data structures? , which contains a good answer of basic data-structures. Then think about how to model them in C++:
struct Node {
int data;
Node * next;
};
Basically that's all you need to implement a list! (a very simple one). Yet it has no abstractions, you have to link the items per hand:
Node a={1}, b={20, &a}, c={35, &b} d={42, &c};
Now, you have have a linked list of nodes, all allocated on the stack:
d -> c -> b -> a
42 35 20 1
Next step is to write a wrapper class List that points to the start node, and allows to add nodes as needed, keeping track of the head of the list (the following is very simplified):
class List {
struct Node {
int data;
Node * next;
};
Node * head;
public:
List() {
head = NULL;
}
~List() {
while(head != NULL) {
Node * n = head->next;
delete head;
head = n;
}
}
void add(int value) {
Node * n = new Node;
n->data = value;
n->next = head;
head = n;
}
// ...
};
Next step is to make the List a template, so that you can stuff other values (not only integers).
If you are familiar with smart pointers, you can then replace the raw pointers used with smart pointers. Often i find people recommend smart pointers to starters. But in my opinion you should first understand why you need smart pointers, and then use them. But that requires that you need first understand raw pointers. Otherwise, you use some magic tool, without knowing why you need it.
You should really use the standard List class. Unless, of course, this is a homework question, or you want to know how lists are implemented by STL.
You'll find plenty of simple tutorials via google, like this one. If you want to know how linked lists work "under the hood", try searching for C list examples/tutorials rather than C++.
If you are going to use std::list, you need to pass a type parameter:
list<int> intList;
list<int>* intListPtr = new list<int>;
If you want to know how lists work, I recommending googling for some C/C++ tutorials to gain an understanding of that subject. Next step would then be learning enough C++ to create a list class, and finally a list template class.
If you have more questions, ask back here.
Why reinvent the wheel. Just use the STL list container.
#include <list>
// in some function, you now do...
std::list<int> mylist; // integer list
More information...
I'm guessing this is a homework question, so you probably want to go here. It has a tutorial explaining linked lists, gives good pseudocode and also has a C++ implementation you can download.
I'd recommend reading through the explanation and understanding the pseudocode before blindly using the implementation. This is a topic that you really should understand in depth if you want to continue on in CS.
Boost ptr_list
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_list.html
HTH
Create list using C++ templates
i.e
template <class T> struct Node
{
T data;
Node * next;
};
template <class T> class List
{
Node<T> *head,*tail;
public:
void push(T const&); // push element
void pop(); // pop element
bool empty() // return true if empty.
};
Then you can write the code like:
List<MyClass>;
The type T is not dynamic in run time.It is only for the compile time.
For complete example click here.
For C++ templates tutorial click here.
We are already in 21st century!!
Don't try to implement the already existing data structures.
Try to use the existing data structures.
Use STL or Boost library