I am pretty new with C++ and I wanted to make sure that I have set up my linked list currently. The information was stored in a vector before, but I was assigned to change it to a linked list. The information stored is CandidateInfo, here is the original code. Have I set my list up correctly?
struct CandidateInfo {
std::string name;
int votesInThisState;
int delegatesWonInThisState; };
std::vector<CandidateInfo> stateCandidates;
And here is my attempet. Suggestions welcomed.
template <typename StatePrimary>
struct CandidateInfo
{
std::string name;
int votesInThisState;
int delegatesWonInThisState;
StatePrimary state;
CandidateInfo<StatePrimary>* next;
CandidateInfo()
{
next = 0;
}
CandidateInfo
(const StatePrimary& c,
CandidateInfo<StatePrimary>* nxt =0)
: state(c), next(nxt)
{}
};
template <typename StatePrimary>
struct CandidateInfoHeader
{
CandidateInfo<StatePrimary>* first;
CandidateInfoHeader();
};
I would have put this as a comment, but I don't have enough reputation yet. Is there a reason you're not using a std::list? That way you could use the code in the first snippet you posted, i.e.:
struct CandidateInfo {
std::string name;
int votesInThisState;
int delegatesWonInThisState; };
std::list<CandidateInfo> stateCandidates;
(Note the change from vector to list in the last line)
std::list is an STL implementation of a doubly linked list.
Related
struct Element{
Element() {}
int data = NULL;
struct Element* right, *left;
};
or
struct Element{
Element() {}
int data = NULL;
Element* right, *left;
};
I was working with binary trees and I was looking up on an example. In the example, Element* right was struct Element* right. What are the differences between these and which one would be better for writing data structures?
I was looking up from this website:
https://www.geeksforgeeks.org/binary-tree-set-1-introduction/
In C, struct keyword must be used for declaring structure variables, but it is optional(in most cases) in C++.
Consider the following examples:
struct Foo
{
int data;
Foo* temp; // Error in C, struct must be there. Works in C++
};
int main()
{
Foo a; // Error in C, struct must be there. Works in C++
return 0;
}
Example 2
struct Foo
{
int data;
struct Foo* temp; // Works in both C and C++
};
int main()
{
struct Foo a; // Works in both C and C++
return 0;
}
In the above examples, temp is a data member that is a pointer to non-const Foo.
Additionally, i would recommend using some good C++ book to learn C++.
In C++, defining a class also defines a type with the same name so using struct Element or just Element means the same thing.
// The typedef below is not needed in C++ but in C to not have to use "struct Element":
typedef struct Element Element;
struct Element {
Element* prev;
Element* next;
};
You rarely have to use struct Element (other than in the definition) in C++.
There is however one situation where you do need it and that is when you need to disambiguate between a type and a function with the same name:
struct Element {};
void Element() {}
int main() {
Element x; // error, "struct Element" needed
}
I have been solving a question, Dijkstra's Algorithm, in C++. I've implemented it using adjacency list.
So I have a class for a node, a class for a minHeap, and a class for the Graph.
class node
{
int vertex,weight;
node *next;
friend class Graph;
friend class minHeap;
public:
node();
node(int,int);
};
node::node(){
vertex=weight=0;
next=0;
}
node::node(int v,int wt){
vertex=v;
weight=wt;
next=0;
}
Do I define the minHeap class this way (without a friend function) and create an object in the getDijkSP() function normally, which allows me to use the object only in that function?
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap];
heapSize=-1;
pos=new int[cap]();
} //eliminating other methods
class Graph
{
node **adjList;
int v;
bool *visited;
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
}
void Graph::getDijkSP(){
minHeap hp(v); //here
hp.addElement(node(0,0));
for(int i=1;i<v;i++)
hp.addElement(node(i,INT_MAX));
while(!hp.isempty()){
node temp=hp.extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp.decreaseKey(current->vertex,current->weight+temp.weight);
}
}
(OR) Do I define the minHeap class with a friend function, so that I can create an object of the minHeap class using the new keyword? (And this helps me define the minHeap object in the scope of the Graph class, so that I can use it in all of its functions for other capabilities as well.)
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
friend class Graph; //say like this
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap]();
heapSize=-1;
pos=new int[cap]();
}
class Graph
{
node **adjList;
int v;
bool *visited;
minHeap *hp; //and do this
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
hp=new minHeap(v); //dynamic allocation
}
void Graph::getDijkSP(){
hp->addElement(node(0,0));
for(int i=1;i<v;i++)
hp->addElement(node(i,INT_MAX));
while(!hp->isempty()){
node temp=hp->extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp->decreaseKey(current->vertex,current->weight+temp.weight);
}
}
I have read this and a few other articles, but specifically want to know the advantages, disadvantages and the appropriateness of both the methods for such similar kinds of questions.
I've provided the constructors for the classes for better clarity.
Short answer would be NO. I would suggest you to read up on smart pointers and rewrite this whole mess. In C++ there is no real reason to use manual allocation in so simple project as this ever.
Also instead of assigning 0 or NULL to a pointer use nullptr, which is C++ symbol only for null pointers unlike the previous mentioned C values that are actually just a int 0 which may cause some unintentional errors.
Edit in response to your comment:
So I've decided to rewrite your code using actual modern C++ instead of this C code with simple classes. In your whole example there are almost no pointers or dynamic allocations needed. I wasn't absolutely sure who exactly should own the actual nodes so from the example I assumed that the MinHeap should. Also I didn't get the point of MinHeap::pos and Graph::visited from what I could see. I can explain any part of that code in more detail, just ask which.
Here is the code:
class Node {
// Only friend class required if you insist on keeping members of Node private.
// If they aren't meant to change, consider declaring them as public and const.
template <unsigned Size> friend class Graph;
public:
Node(int v, int wt) : vertex(v), weight(wt) {}
private:
// Default values written in here right after declarations
// There is no need for a default constructor. You never call it anyway.
int vertex;
int weight;
Node* next = nullptr;
};
// Template parameter because of internal use of std::array.
// If the capacity shouldn't be constant, use std::vector and remove template.
template <unsigned Capacity>
class MinHeap {
public:
// No constructor needed
// ---------------------
// One small tip: write parameter names in function declarations
// even if they aren't needed there for better readability of your code.
void addElement(Node n) { /* impl */ }
Node extractMin() { /* impl */ }
unsigned capacity() { return Capacity; }
bool isEmpty() { return heap.isEmpty(); }
private:
// Default values written in here right after declarations
int heapSize = -1;
std::array<Node, Capacity> heap;
};
// Template parameter because of internal use of std::array.
// If the vertex count shouldn't be constant, use std::vector and remove template.
template <unsigned Vertices>
class Graph {
public:
// No constructor needed
// ---------------------
void getDjikSP() {
hp.addElement({0, 0});
for (unsigned i = 1; i < hp.capacity(); ++i)
hp.addElement({0, INT_MAX});
while (!hp.isEmpty()) {
Node tmp = hp.extractMin();
std::cout << tmp.vertex << " " << tmp.weight << std::endl;
for (Node* current = adjList[tmp.vertex]; current != nullptr; current = current->next)
hp.decreaseKey(current->vertex, current->weight + tmp.weight);
}
}
private:
// Default values written in here right after declarations
std::array<Node*, Vertices> adjList;
MinHeap<Vertices> hp;
};
There is still a lot of space for improvements of this code, for example the MinHeaP::extractMin should maybe return Node&& if it is removed from the heap or const Node& if it should return a reference to the top, etc. To address all the problems and inefficiencies this can still have I would need to see the full code with all functions.
I have the following class:
typedef struct Listable
{
struct Listable *next;
struct Listable *prev;
// Lots of other class members not pertaining to the question excluded here
} Listable;
and I inherit from it like so:
typedef struct Object : Listable
{
} Object;
Problem is, when I do something like this:
Object *node;
for (node = objectHead; node; node = node->next);
I get an error with 'node = node->next', since node->next is of type Listable, while node is of type Object.
How can I use templates in the Listable base class to make the prev & next pointers change their type to the class being used?
Perhaps something like:
typedef struct Listable<T>
{
struct Listable<T> *next;
struct Listable<T> *prev;
// Lots of other class members not pertaining to the question excluded here
} Listable;
and I inherit from it like so:
typedef struct Object : Listable<Object>
{
} Object;
I have over 10 years of C, but am fairly new to C++ features like templates. So I'm not sure what syntax I should be using.
The template syntax itself is fairly straight forward:
template <typename T>
struct Listable
{
T *next;
T *prev;
// Lots of other class members not pertaining to the question excluded here
};
So, when it gets inherited by Object like this:
struct Object : Listable<Object>
{
};
Object will get the next and prev pointers.
Since Listable is managing pointers, you will need to pay attention to the Rule of Three. That is, you have to think about what needs to be done during destruction, copy construction, and assignment so that memory is managed properly.
Are you sure you would rather not just use:
Listable *node;
for (node = objectHead; node; node = node->next);
instead? That would work even if node is actually an Object, because Object inherits from Listable.
Also, as Jerry mentions, there already is a built-in templated, doubly linked list that is part of the C++ Standard Template Library. You would not need to manually write a for loop either, because you could also use std::foreach to operate on it:
#include <list>
#include <algorithm>
#include <iostream>
struct Sum {
Sum() { sum = 0; }
void operator()(int n) { sum += n; }
int sum;
};
int main()
{
std::list<int> nums{3, 4, 2, 9, 15, 267};
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "sum: " << s.sum << '\n';
std::cout << "elements: ";
//Or, you could use iterate over each node in the list like this
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
}
You seem to be conflating the notion of of a linked list with that of a node in the linked list. Then you're adding in an Object that (supposedly) is one of these confused node/linked list things. At least to me, this sounds quite confused and confusing.
I'd prefer to see something like:
template <class T>
class linked_list {
class node {
T data;
node *next;
public:
node(T data, node *next = NULL) : data(data), next(next) {}
};
node *head;
public:
void push_back(T const &item);
void push_font(T const &item);
// etc.
};
Caveat: of course, for real code you 1) probably don't want to use a linked list at all, and 2) even if you do, it should probably be a std::list.
I have the following in an implementation file...
void ClientList::interestCompare(vector<string> intr)
{
for(int index = 0; index < intr.size(); index++)
{
this->interests[index];
}
}
and this in the specification file...
class ClientList
{
private:
// A structure for the list
struct ListNode
{
char gender;
string name;
string phone;
int numInterests; // The number of interests for the client
vector<string> interests; // list of interests
string match;
struct ListNode *next; // To point to the next node
};
//more stuff
...}
is it possible to use the "this" pointer to access the "interests" vector in the struct?
If so how.
As I have it now, I initialize a ListNode pointer to head in order to access the list. I'm just wondering if the "this" pointer can only access members of the class, or if they can access deeper ADT variables embedded in the class.
Does that question even make sense?
You only declared a ListNode type inside ClientList class which doesn't mean you have a instance of ClientList. As you hare using std::vector already, you could use std::vector or std::list instead of implementing another list
class ClientList
{
private:
// A structure for the list
struct Client
{
char gender;
std::string name;
std::string phone;
int numInterests; // The number of interests for the client
std::vector<string> interests; // list of interests
std::string match;
};
std::vector<Client> clients;
//more stuff
};
Edit:
If you want to compare two lists, use std::set_intersection, it requires two containers to be sorted in place.
void ClientList::FindClientHasCommonInterest(const vector<string>& intr)
{
for(auto client = clients.begin(); client != clients.end(); ++client)
{
std::vector<std::string> intereste_in_common;
std::set_intersection((*client).begin(), (*client).end(),
intr.begin(), intr.end(),
std::back_inserter(intereste_in_common));
if (intereste_in_common.size() >= 3)
{
// find one client
}
}
}
No, it's different between Java and C++ for nested class. C++ nested class is essentially the same as static nested class in Java. So, you have to use an instance of the nested struct to access its member.
Some code for context:
class WordTable
{
public:
WordTable();
~WordTable();
List* GetListByAlphaKey(char key);
void AddListByKey(char key);
bool ListExists(char key);
bool WordExists(string word);
void AddWord(string word);
void IncrementWordOccurances(string word);
void Print();
private:
List *_listArray[33];
int _GetIndexByKey(char key);
};
class TableBuilder
{
public:
TableBuilder();
~TableBuilder();
void AnalyzeStream(fstream &inputStream);
void PrintResults();
private:
void _AnalyzeCursor(string data);
bool _WordIsValid(string data);
WordTable* _WordTable;
};
struct Element {
public:
string Word;
int Occurances;
Element* Next;
};
class List
{
public:
List();
~List();
Element* AddElement(string word);
void DeleteElement(Element* element);
void Print();
void Delete();
Element* First;
bool WordExists(string word);
void IncrementWordOccurances(string word);
private:
void _PrintElementDetails(Element* element);
};
Requirements
I must analyze text, building array of linked lists (where array contains list for each letter; list contains every word found in text), then print out results.
Problem
I can`t initialize array of lists in WordTable.cpp. I know that i've misunderstood something, but i got no ideas and time. Anyone?
P.s. Yeah, that's a homework. STOP giving me advices about best practices, please... :)
An initialization for _listArray would look like this:
WordTable::WordTable() {
for (int i=0; i<33; i++)
_listArray[i] = new List();
}
You don't really say what exactly the problem is so I'm not sure if this helps...
It's because you're creating an array of pointers to lists. Either change it to List _listArray[33]; or initialize it like so:
for ( int i = 0; i < 33; ++i ) {
_listArray[i] = new List();
}
// and to access methods
_listArray[i]->AddElement( "word" );
It appears you are optimizing your linked lists by having an array of them, one for each first letter of the word. Don't do that.
Use std::map. Where the string is the word and the int is your count.
EDIT: If you ignore my advice... As has been pointed out your _listArray is actually an array of pointers, not an array of objects. I think you wanted an array of objects. Since the array is fixed length, and List has a default constructor, the simplest way to do that is to just say
List _listArray[33];
If you want dynamic allocation, you could do this instead:
List* _listArray;
And in the constructor:
_listArray = new List[33];
And in the destructor:
delete[] _listArray;
Please don't reinvent the wheel (again)
Use std::list it works correctly, is safer, is standard.
Second : you have design problems : element attribute in list is public, but you have a private method ???.