• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

C++ help

Status
Not open for further replies.
Level 23
Joined
Apr 16, 2012
Messages
4,041
Well, I was coding a bit and made something that I consider being Linked List :D Dont know if it really can be clasified as one but well...meh.

I have done some benchmarking, and I found out that while push works very fast(1000 pushes in 1 ms), pop is a very slow(7 ms for 1000 pops). At higher rates, the pop slows done until it gets to around 77,4x slower then push(1 mil calls).
So I want to ask for any suggestions on imrpvoing either functionality(more functions or less functions) and some points to optimization(if any)


C++:
//#define DEBUG_MODE

/*
	template <class T>
	class node{
		node* next;
		node* prev;
		T v; <-- variable stored in the list
	Methods:

	node()
	~node()
	void push(T value)
	T pop()
	node* getnext()
	node* getprev()
	bool isEmpty()
	T pop(int frompos)
	T seek()
	int getNodesCount()
	T seek(int fromposition)
	void push(T value, int position)
	void push(T value, int position)
	void copyList(node* copyinto)
	void clear()

*/

#define UNUSED_RETURN_VALUE -1

namespace glo{

	template <class T>
	class node{
		node* next;
		node* prev;
		T v;
	public:
		node()
		{
			next = null;
			prev = null;
		}
		~node()
		{
			node* a = null;
			while(this->next != null)
			{
				a = this->next->next;
				this->next->next = null;
				this->next->prev = null;
				if (this->next)
					delete this->next;
				
				this->next = a;
			}
			a = null;
		}
		void push(T value)
		{
			node* n = this->next;
			this->next = null;
			this->next = new node;
			if (n != null)
				n->prev = this->next;
			
			this->next->next = n;
			this->next->v = value;
			n = null;
		}
		T pop()
		{
			if (this->next == null)	return UNUSED_RETURN_VALUE;
			T i = this->next->v;
			node* n = this->next->next;
			this->next->next = null;
			this->next->prev = null;
			delete this->next;
			this->next = n;
			n = null;
			return i;
		}
		node* getnext()
		{
			if (this->next == null)	return this;
			return this->next;
		}
		node* getprev()
		{
			if (this->prev == null)	return this;
			return this->prev;
		}
		bool isEmpty()
		{
			return this->next != null ? false : true;
		}
		T pop(int frompos)
		{
			if (frompos <= 0)
				return UNUSED_RETURN_VALUE;
			else if (frompos == 1)
				return this->pop();


			node* n = this;
			while(n->prev != null)
			{
				n = n->prev;
			}
			while(frompos-- > 1 && n->next->next != null)
			{
				n = n->next;
			}
			return n->pop();
		}
		T seek()
		{
			if (this->next == null)	return null;
			return this->next->v;
		}
		int getNodesCount()
		{
			int i = 0;
			node* n = this;
			while(n->next != null)
			{
				i++;
				n = n->next;
			}
			return i;
		}
		T seek(int fromposition)
		{
			if (fromposition <= 0)	return UNUSED_RETURN_VALUE;
			node *n = this;
			//ensuring that the node is the first on the list:
			//in debug mode
		#ifdef DEBUG_MODE
			while(n->prev != null)
			{
				n = n->prev;
			}
		#endif
			//							safety for overflow
			while(fromposition-- > 1 && n->next != null)
			{
				n = n->next;
			}
			return n->seek();
		}
		void push(T value, int position)
		{
			node* n = this;
			while(n->prev != null)
			{
				n = n->prev;
			}
			while(position-- > 1 && n->next != null)
			{
				n = n->next;
			}
			n->push(value);
			n = null;
		}
		void copyList(node* copyinto)
		{
			if (copyinto == null)	return;
			int itter = this->getNodesCount()+1;
			node* n = this;
			while(itter-- > 1)
			{
				copyinto->push(n->seek(itter));
			}
			n = null;
		}
		void clear()
		{
			while(!isEmpty())
			{
				pop();
			}
		}
		void swap()
		{
			node* n = new node;
			while(!isEmpty())
				n->push(pop(getNodesCount()+1));

			while(!n->isEmpty())
			{
				push(n->pop());
			}
                        delete n;
		}
	};	//node<T>

}; //glo

(I am fully aware that swap() is damn slow, I will do my best to make it faster, currently runs at ~0,3 ms with 100 items in list)
(null is defined as NULL, which is defined as either 0(C++) or ((void)*0) (C)
Also I considered making the value pointer but it was for some reason not working :/

All help is greatly appreciated
 
Last edited:
The problem is that node::push is calling the destructor of the class, which has O(n) complexity.

Honestly, a better model of a list class would be this:

C++:
// You can encapsulate the members of the class if you want.
template<class T>
class Node {
    public:
        Node<T>* next;
        Node<T>* prev;
        
        T value;

        Node();
        Node(T value);
        ~Node();
};

template<class T>
class List {
    private:
        Node<T>* root;

    public:
        List();
        ~List();

        // O(1)
        Node<T>* getFirst();

        // O(1)
        void insertNode(Node<T>* node);
        // O(1)
        void removeNode(Node<T>* node);

        // O(1)
        void insertValue(T value);

        // O(n) but can be O(log n)
        void removeValue(T value);
};
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
A linked list should always be made of 2 parts.
1. An interface class that manages the linked list. This allows the caching of some values such as start, end and size (solves the length problem by making it O(1) instead of O(n)).
2. A node class that basicly acts as the implementation and actual linked list elements. This is invisible to the user (they only see 1. the interface class).

An advantage of this approach is that you could easilly replaced a linked list with an array list or any other type of list (even with behaviour differences like FIFO or LIFO).

For efficiency you may want to allocate nodes pages at a time. This saves on malloc allocation data potentially allowing for more memory efficiency and also makes allocation faster (allocating a page is faster than malloc allocating a page and fragmenting it). There is a problem of fragmentation however so you should be sure to fill hole pages before moving to free space on next pages. For your level of programming you may want to ignore this although heavilly utalized implemtations will see a benifit from this.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I made something like this:

C++:
namespace lis{

	template <class T>
	class List;
	
	template <class T>
	class Node{
		Node<T>* next;
		Node<T>* prev;
		inline void init()
		{
			this->next = null;
			this->prev = null;
		}
	public:
		friend class List<T>;
		T value;
		Node()
		{
			init();
		}
		Node(T arg_value)
		{
			init();
			this->value = arg_value;
		}
		~Node()
		{
		}
	};

	template <class T>
	class List{
		Node<T>* root;
	public:
		List()
		{
			root = new Node<T>;
		}
		~List()
		{
			Node<T>* n = root->next;
			while(root->next != null)
			{
				n = n->next;
				delete root->next;
				root->next = n;
			}
			delete root;
		}
		Node<T>* getFirst()
		{
			return root->next;
		}
		T getFirstVal()
		{
			if (root->next == null)	return null;
			T val = root->next->value;
			Node<T>* n = root->next;
			root->next = n->next;
			if (root->next != null)	root->next->prev = root;
			delete n;
			return val;
		}
		void insert(T value)
		{
			Node<T>* n = root->next;
			root->next = new Node<T>(value);
			root->next->next = n;
			if (n != null)	n->prev = root->next;
		}
		bool isEmpty()
		{
			return (root->next == null) ? true : false;
		}
	};
};

which has 1 loop involved(when destructor of List is called it deletes all the trailing Nodes), still the speed is the same as before

Also I have found out that C++ list from list header file is even slower a bit.

Also Ive tested this class in school on windows xp with even slower(a lot) computer then the mine at home and it was actually faster, could it be that windows 7 handles deleting poniters slower then xp for instance?
(on my 7, it was 0.084 ms each at 10000, at school it was 0.061 ms each at same number of calls)

Thank you for your feedback
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
could it be that windows 7 handles deleting poniters slower then xp for instance?
If your Windows 7 machine is 64 bit and the school XP machine is 32 bit then yes, it has to load an extra 4 bytes per pointer which will slow it down. 64 bit machines only gain an advantage in register usage or 64 bit structure manipulation, otherwise they might execute slower.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
they have IBM
Does IBM even make x86 processors?

In any case that is the reason. IBM make damn good stuff. There is a reason their stuff costs an arm and a leg. AMD on the other hand generally makes the worst performing stuff but at the best price to performance ratio (unlike IBM which is usually the worst price to performance ratio but has the best performance).
 
Level 3
Joined
Nov 14, 2010
Messages
27
I have only one question .

Does vJass or Jass (or however its called) programming in c++ , or it is a smaler part of some IDE ?? I mean i have some advanced knownolage in c++ (like 2-3 years of programming) but I lost mine interests while i saw that for vJass you need to have some other modified w3 game (editor). And if vJass is programming outside of a w3 editor ,how to import script in non modified (original) editor? Please replay.
 
Level 8
Joined
Aug 13, 2009
Messages
466
I have only one question .

Does vJass or Jass (or however its called) programming in c++ , or it is a smaler part of some IDE ?? I mean i have some advanced knownolage in c++ (like 2-3 years of programming) but I lost mine interests while i saw that for vJass you need to have some other modified w3 game (editor). And if vJass is programming outside of a w3 editor ,how to import script in non modified (original) editor? Please replay.

Are you for real

Edit: post #111 !1
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
Does vJass or Jass (or however its called) programming in c++ , or it is a smaler part of some IDE ??
vJASS is implemented as a pre-compiler in pearl if I recall correctly.

i saw that for vJass you need to have some other modified w3 game (editor).
JNGP injects code into the 1.21 editor (which means renaming the existing worldedit.exe and replacing it with the 1.21 version worldedit.exe). Nothing else is modified.

And if vJass is programming outside of a w3 editor ,how to import script in non modified (original) editor?
JassHelper converts vJASS script into normal JASS script as that is all the WarCraft III trigger engine can interpret. This script is placed automatically into the primary map script by JNGP when it save a map.
 
Status
Not open for further replies.
Top