Introduction to C + + language learning -- linked list, queue and stack

Posted by Solar on Sun, 20 Feb 2022 18:39:26 +0100


[PS] I learned it in school, and I have learned it in Xinjing before. This blog is only used as personal knowledge sorting and backup. If there are mistakes, please help point out, thank you!

The citation of this article is basically from Starting Out with C++ From Control Structures Through Objects 8th Global Edition

1. Linked List

1.1 what is a linked list?

A linked list is a series of connected nodes, where each node is a data structure. A linked list can grow or shrink in size as the program runs.

A linked list is a series of connected nodes, each of which is a data structure. Similar to the function of array, it is a data structure that stores a series of the same data type.

As shown in the following figure, each element of the linked list is composed of its own data content and (at least) a pointer. This pointer is very important. It carries the address information of the next (or previous) element. This is like having a classmate's home address in your home. As long as you use this address, you can find the location of your classmate's home (the next element). In this way, a "chain" table is formed.

Of course, there must be a head. Therefore, for the first person in this linked list, there should be a pointer to the first element. For the last element newly added to the linked list, it is the last, and there is no address of the next element. Therefore, it generally points to itself first (its pointer points to itself) or a null pointer.

Of course, it is obvious that if I want to find an element in the linked list, I must find it from the beginning, just like the treasure map, find a new treasure and treasure map, and continue to find the next one according to the new treasure map

But for the linked list, each element can be dynamically allocated in the physical memory. Unlike the array, it is allocated with adjacent addresses in the physical memory.

1.2 difference between linked list, Array and Vector

Although the structure of the linked list will be more complex than that of the array, the biggest advantage of the linked list is that it can be changed at will when the program is running, that is, users can increase the number of elements in the linked list and reduce the number of elements. Although the size of the array can be determined by the user, once defined in the program, the size can not be changed. Therefore, it is usually said that the array is "Static" and the linked list is "Dynamic".

Another reason to call the linked list dynamic is that it is better to "maintain", that is, it is very easy for users to add an element somewhere in the linked list. This is also the biggest difference between it and vector. Although the linked list may not be superior to the vector (referring to the code in STL), it still has great advantages in dynamic modification. If a new element is to be added in the middle of the vector, the elements behind this position should be shifted back accordingly. However, the linked list only needs to chain the "chain" (the pointer of the previous element) on itself to add new elements, which is very convenient to maintain. Similarly, to delete this element, you only need to remove the "chain" (the pointer of the previous element) from itself and chain it to the following element to directly "delete" the current element.

Of course, compared with vectors, vectors can also change their size dynamically. Arrays are stored in the stack, while vectors are stored in the heap. The storage positions are inconsistent. However, the execution efficiency of arrays is much higher than that of vectors.

1.3 use linked list

1.3.1 linked list structure

Relatively simple, we can directly use struct to define the structure of a linked list (of course, we can also use class. Struct is used because its structure is relatively simple and there are only member variables):

struct ListNode
{
    double value;    //Data elements in linked list (different data types are allowed)
    ListNode *next;  //A pointer of the same type, used to point to the next structure
};

This looks like a little dolly. This is actually a self referential data structure, which allows each node to generate data structures of the same type as itself.

Of course, as just said, there must be a head, so define a head pointer:

ListNode *head; //Of course, it's best to initialize to a null pointer

1.3.2 encapsulate a linked list class of its own

We can encapsulate this whole into a very simple class (one-way linked list), which contains data elements, corresponding header pointers, corresponding member functions: accessors, delete, change, insert, add and other operations (like writing a library file ourselves):

class NumberList
{
	private:
		struct Node                 //Define linked list structure
		{
			double value;           //Data to store
			struct ListNode *next;  //Pointer to the next linked list element
		};
		Node *head;                 //Head pointer
	    int length;                 //Linked list length
		
	public:
		NumberList() { head = nullptr; length = 0; }  //Constructor, set the header pointer to null pointer, and initialize the length of the linked list to 0
		~NumberList();                    //Deconstruction function
	 	void appendNode(double);          //Add a node at the end of the linked list
		void insertNode(double);          //Add a node in the middle of the linked list
		void deleteNode(double);          //Delete a node
		void displayList() const;         //Accessor, display linked list
};

1.3.3 add a node at the tail (Append)

The principle of adding a node at the end of the linked list is not difficult to understand. For example, figure 12.6 should be placed after 7.9. First set a nodePtr, the pointer is given from the head, and one by one index down to the end node (i.e. the null pointer). At this time, nodePtr points to 7.9. At this time, you only need to point the pointer of 7.9 to 12.6 to complete the addition of nodes

Code implementation:

void NumberList::appendNode(double num)
{
	Node *newNode;        //Create a new pointer - > current node to be added
	Node *nodePtr;        //Create a new pointer - > used to search the end node
	
	newNode = new Node;   //Apply for space and instantiate a structure
	newNode->value = num;     //The value of the new node is the value passed in
	newNode->next = nullptr;  
	//Since the new node is the node at the end of the current linked list, there is no next point it points to, so its own pointer is set as a null pointer
	
	if (!head)                //If there is no node in this linked list, the newly added node will be set as the head node
	    head = newNode;
	else                      //If you already have a node, you need to find the last node that has not been updated
	{
		nodePtr = head;       //Get the address of the header node first 
		
		while (nodePtr->next) //Look down one by one according to the address until you encounter a null pointer (the description is at the end)
	        nodePtr = nodePtr->next;
	        
	    nodePtr->next = newNode; //Point the pointer of the last node to the newly added node
	}
	length++; //Linked list length update
}

1.3.4 insert an element in the middle

The insertion method is easy to understand. For example, to insert 10.5 between 7.9 and 12.6, you only need to point the pointer of 7.9 to 10.5, and then point the pointer of 10.5 to 12.6 to complete the insertion.

This is the advantage of the linked list. The code implementation can be written as follows:

void NumberList::insertNode(double pos, double num)
{
	Node *newNode;                //Create a new pointer - > node to be inserted
	Node *nodePtr;                //Create a new pointer - > used to traverse the linked list
	Node *previousNode = nullptr; //Create a new pointer - > used to store the previous node

	newNode = new Node;  //Apply for space and instantiate the structure
	newNode->value = num;    //Writes the value to the new node
	
	if (!head)  //If there is no node, it defaults to the first node and explains
	{
		cout<<"No node in the list, considering as the first node"<<endl;
		head = newNode;
		head->next = nullptr;
	}
	else
	{
		if (pos == 0)  //If you insert a new node directly into the head
		{
			newNode->next = head; //Point the pointer of the new node to the original header
			head = newNode;       //Update header pointer to this new node
		} 
		else
		{
			nodePtr = head;  //Give the head pointer first

			while (nodePtr->next && cnt < pos)  //Find the node of the input location
			{
				previousNode = nodePtr;   //Continuously update the previous node
				nodePtr = nodePtr->next;  //Keep looking for the next node
				cnt++;                    //Count, the number of the linked list
			}
		
			if (cnt < pos)  //If it does not reach the set position, it means that the length of the linked list is too short. By default, the node is set to the end of the linked list
			{
				cout<<"Warning: Insert "<<pos<<": Number would be inserted to the end of the list."<<endl;
			newNode->next = nullptr;
			nodePtr->next = newNode;
			}
			else  //If found, insert the node directly between the previousNode and NodePtr
			{
				previousNode->next = newNode;
				newNode->next = nodePtr;
			}
		}
	length++; //Linked list length update
}

1.3.5 delete an element in the middle

The method of deleting an element is also very simple. You only need to point the pointer of the previous node to the node pointed to by the current pointer to delete the current node. For example, to delete 7.9 from the middle, you only need to point the pointer of 2.5 to 12.6. In this way, the address of 7.9 is lost, so it cannot be indexed. It seems to be "deleted".

Code implementation:

void NumberList::deleteNode(int pos) //Delete the position in the given linked list
{
	int cnt = 0;   //Count, the number of nodes in the linked list
	Node *nodePtr; //Set new pointer - > for traversal  
	Node *previousNode = nullptr; //Set new pointer - > used to update the previous pointer of traversal pointer in real time

	if (!head)  //If the linked list is still empty, you cannot delete it
	{
		cout<<"The list is empty!"<<endl;
		return;
	} 
	else
	{
		if (pos == 0)  //If you want to delete the head of the linked list
		{
			nodePtr = head->next;
			delete head;
			head = nodePtr;
		}
		else
		{
			while(nodePtr != nullptr && cnt < pos)  //Index down to the corresponding position
			{
				previousNode = nodePtr;
				nodePtr = nodePtr->next;
				cnt++;
			}
			
			if(cnt < pos) //If the index is less than the input position, the linked list is too short. The last node of the linked list is deleted by default
			{
				cout<<"Warning: Delete "<<pos<<": "<<"The end of the list would be deleted."<<endl;
				previousNode->next = nullptr;
				delete nodePtr;
			}
			else
			{
				previousNode->next = nodePtr->next;
			}
		}
	}
	length--; //Linked list length update
}

1.3.6 display linked list

As mentioned in the previous article, the class needs an Accessor to access the values in the linked list. Therefore, it is necessary to display the member functions of the linked list. Of course, here is only the value of each node and the length of the linked list.

Code implementation:

void NumberList::displayList() const
{
	Node *nodePtr;
	nodePtr = head; //Index from header
	while (nodePtr)
	{
		cout<<nodePtr->value<<endl;  //Each node outputs a value
		nodePtr = nodePtr->next;     //Continue indexing next node
	}
	cout<<"Total number in the list: "<<length<<endl; //Display the length of the linked list
}

1.3.7 testing

This class will be tested, test code:

int main()
{
	NumberList list;          //Instantiate a linked list class
	list.appendNode(5.6);     //Add node at the end
	list.appendNode(7.2);
	list.insertNode(0,3.3);   //Head insert node
	list.insertNode(0,5.6);
	list.insertNode(2,9.9);
	list.insertNode(6,12.38); //The test adds nodes at the tail by default
	list.displayList();
	cout<<endl;
	list.deleteNode(0);       //Delete header node
	list.deleteNode(2);       //Delete intermediate node
	list.deleteNode(8);       //The test deletes the node at the end by default
	list.displayList();
}

result:

Warning: Insert 6: Number would be inserted to the end of the list.
5.6
3.3
9.9
5.6
7.2
12.38
Total number in the list: 6

Warning: Delete 8: The end of the list would be deleted.
3.3
5.6
7.2
Total number in the list: 3

The linked list class can be written as a Template for later nesting and use

1.4 type of linked list

There are many types of linked lists, which are designed according to different functions.

1.4.1 singly linked lists

Just defined above is a one-way linked list, that is, each node only contains the information of the address of the next node. Of course, the single linked list can be reversed, that is, the last node points forward one by one.

1.4.2 double linked list

Bidirectional linked list, as the name suggests, is a node that contains the address information of the previous node and the next node at the same time. In this way, you can index forward or backward.

1.4.3 circular linked list

Circular linked list is a closed loop between nodes, and each node points to the next to form a closed loop.

1.5 STL List Library

For linked lists, there are ready-made mature libraries in the C + + standard library, which can be called directly. List is a two-way linked list.

Library declaration:
#include <list>

Transfer from C++ list usage . Corresponding member function:

Instantiate a linked list:
list<int> myList; //Generate a linked list of int

Related member function
assign()            //Assign value to list 
back()              //Returns the last element 
begin()             //Returns an iterator that points to the first element 
clear()             //Delete all elements 
empty()             //If the list is empty, it returns true; otherwise, it returns false
end()               //Returns the iterator at the end 
erase(x)/erase(x,y) //Delete paragraph 
front()             //Returns the first element 
get_allocator()     //Returns the configurator of the list 
insert()            //Insert an element into the list 
max_size()          //Returns the maximum number of elements that the list can hold 
merge()             //Merge two list s 
pop_back()          //Delete last element 
pop_front()         //Delete the first element 
push_back()         //Add an element at the end of the list 
push_front()        //Add an element to the head of the list 
remove()            //Delete element from list 
remove_if()         //Delete elements according to specified conditions 
resize()            //Change the size of the list 
reverse()           //Invert the elements of the list 
size()              //Returns the number of elements in the list 
sort()              //Sort list 
swap()              //Swap two list s 
unique()            //Delete duplicate elements in the list

2. Queue

2.1 what is a queue?

2.2 STL Queue library

3. Stack

3.1 what is stack?

3.2 STL Stack Library

Topics: C++ data structure linked list