Single linked list C + + version of data structure

Keywords: C++ data structure linked list

Single linked list C + + version of data structure


There is an STL list in C + +. The bottom layer is a two-way linked list. Here, a single linked list is written to play.

Included header file

#include <iostream>

Nothing else. If you want to be more rigorous, add a new header file

#include <new>

Structure description linked list node

struct Node
{
	int data;
	Node* next;
	Node(int data = 0):data(data),next(nullptr){}
};

Because C + + can directly use the structure name to define the structure variable, there is no need to use typedef as an alias.

List repackaging

class List
{
public:
    //Constructor
	List()
	{
		this->size = 0;
		this->headNode = nullptr;
	}
    //Destructor
	~List()
	{
		clear();	//Clean up nodes in the linked list
		delete[] this->headNode;	//Free header node memory
	}
	int getSize() { return this->size; }		//Gets the size of the current linked list
	bool empty() { return this->size == 0; }	//Determine whether the linked list is empty
	void push_front(int data);					//Insert data by head interpolation
	void push_back(int data);					//Inserting data by tail interpolation
	void insertByPos(int pos, int data);		//Insert data at the specified location
	void print_front();							//Print data in linked list
	void clear();								//Clean up nodes in the linked list
	void pop_front();							//Delete nodes from the head of the linked list
	void pop_back();							//Delete nodes from the end of the linked list
	void deleteByPos(int pos);					//Delete node at specified location
	bool scearch(int num);						//Find data in linked list
	void changeData(int newNum, int pos);		//Modify data at the specified location
protected:
	int size;			//Panacea parameter, the size of the current linked list
	Node* headNode;		//Point to the head node of the linked list
};

Such a linked list has been written. The next thing is to implement the member functions in the linked list one by one.

Implementation of each member function

For reference only

Gets the size of the current linked list

Directly return the size data member in the List class. The size data member is initialized to zero by default when calling the constructor at the beginning, and then the corresponding self increment and self decrement operations will be carried out during the addition and deletion operations.

int getSize() { return this->size; }

Determine whether the linked list is empty

Directly judge whether the size member is zero. If it is zero, return true and if it is not zero, return false.

bool empty() { return this->size == 0; }

Insert data by head interpolation

Receive a data to be inserted from the outside, and then dynamically apply for a node's memory newNode in the function to judge whether the linked list is empty. If it is empty, directly point the head node pointer of the linked list to the newNode. If it is not empty, connect first and then move the head node position to prevent chain breakage. Don't forget to increment the size attribute after the connection is completed.

void List::push_front(int data)
{
	Node* newNode = new Node(data);
	if (this->size == 0)
	{
		this->headNode = newNode;
	}
	else
	{
		newNode->next = this->headNode;
		this->headNode = newNode;
	}
	this->size++;
}

Inserting data by tail interpolation

Receive a data from the outside to initialize the data data in the node, and then apply for a memory newNode in the function to judge whether the linked list is empty. If it is empty, directly point the pointer of the head node of the linked list to the newNode. If it is not empty, define a moving pointer pMove, let pMove go to the end of the list, and then directly point the pMove - > next pointer to newNdoe, This completes the link. Still the same, after the new node is connected to the linked list, don't forget to do the self increment operation for the size attribute.

void List::push_back(int data)
{
	Node* newNode = new Node(data);
	if (this->size == 0)
	{
		this->headNode = newNode;
	}
	else
	{
		Node* pMove = this->headNode;
		while (pMove->next != nullptr)
		{
			pMove = pMove->next;
		}
		pMove->next = newNode;
	}
	this->size++;
}

Insert data at the specified location

In addition to a node data attribute, the parameters of this function also need a POS data to represent the nodes of the linked list. After entering the function, first judge whether the size attribute is zero, because if the size attribute is zero, there is no coordinate POS, and there is no coordinate in memory. Then it is whether the POS is within the size attribute range. If it is beyond the control of size, you can directly end the whole function. The above situation is not satisfied, that is, directly judge whether POS is 0. If it is zero, directly call the header insertion function that has been written. If POS is just equal to size, call the function that inserts data with the footer method. The last is the range of pos from 1 to size-1 nodes. Use a moving pointer pMove to traverse the linked list until the node corresponding to POS is traversed. This is done with a loop. When you jump out of the loop, you can directly insert a new node on the left of the node corresponding to POS or on the right of it. It depends on your personal ideas and how you want to insert it.

void List::insertByPos(int pos, int data)
{
	if (this->size == 0 || pos > this->size || pos < 0)
		return;
	else if (pos == 0)
		push_front(data);
	else if (pos == this->size)
		push_back(data);
	else
	{
		Node* pMove = this->headNode;
		Node* newNode = new Node(data);
		while (pos > 0)
		{
			pMove = pMove->next;
			pos--;
		}
		newNode->next = pMove->next;
		pMove->next = newNode;
		this->size++;
	}
}

Print data in linked list

Because the linked list is a single linked list, you can only print the data of the linked list from scratch. The idea is very simple, that is, use a moving pointer to traverse the whole linked list and print while moving until the moving pointer pMove points to null. Finally, you can have a new line to make the result look better.

void List::print_front()
{
	Node* pMove = this->headNode;
	while (pMove != nullptr)
	{
		cout << pMove->data << '\t';
		pMove = pMove->next;
	}
	cout << endl;
}

Clean up nodes in the linked list

This is the same as writing a single linked list like C language at the beginning. In fact, the idea is to let the moving pointer traverse the linked list, delete the pointer for recording, delete the node pointed to by the deleted pointer after recording, and traverse to the end of the linked list. The head node is not deleted at the beginning to prevent chain breakage. Because calling clear function in this program is called at the time of destructor, so the size attribute set is not zero, which is not a big problem, because when I call this function, I do not want this list.

void List::clear()
{
	Node* pDelete;
	Node* pMove = this->headNode->next;
	while (pMove != nullptr)
	{
		pDelete = pMove;
		pMove = pMove->next;
		delete pDelete;
		pDelete = nullptr;
	}
}

Delete nodes from the head of the linked list

The difference from the above clear function is that the above clear function releases all the nodes in the linked list. At present, this function will only delete the head node. Make a record before deleting the head node. After recording, let the head node point to write a node, and finally delete the node just recorded. This is the idea of the whole function. Remember to subtract the size attribute after deleting it.

void List::pop_front()
{
	Node* pDelete = this->headNode;
	this->headNode = this->headNode->next;
	pDelete->next = nullptr;
	delete pDelete;
	pDelete = nullptr;
	this->size--;
}

Delete nodes from the end of the linked list

Because the single linked list can only go back from the beginning and cannot go backwards, first define a moving pointer pMove and a recording pointer pMove_left, when pMove - > next points to null, it means that pMove has reached the last node of the linked list, and then it can be deleted. pMove is directly used for deletion_ Left - > next points to null or pMove - > next, and then release the pMove pointer.

void List::pop_back()
{
	Node* pMove_left = this->headNode;
	Node* pMove = this->headNode->next;
	while (pMove->next != nullptr)
	{
		pMove_left = pMove;
		pMove = pMove->next;
	}
	pMove_left->next = nullptr;
	delete pMove;
	pMove = nullptr;
	this->size--;
}

Delete node at specified location

Since it is a specified location, a pos data must be used to represent the coordinates. After passing in, judge whether the pos is within the range that size can manage. If not, directly end the whole function. If pos is equal to 0 or equal to size, directly call the corresponding pop_front function or pop_back function. Finally, it is in the range of 1 to size-1. The idea is also very simple. Define a moving pointer pMove for traversal, and a pointer pMove_left is used to record the nodes pMove has passed. After you reach the pos position, use pMove_left - > next points to pMove - > next, then pMove - > next points to null, then releases the memory in pMove, and finally pMove points to null. In this way, the deletion of the specified location is completed. Finally, don't forget to perform the self subtraction operation for the size attribute.

void List::deleteByPos(int pos)
{
	if (pos<0 || pos>this->size)
		return;
	else if (pos == 0)
		pop_front();
	else if (pos == this->size)
		pop_back();
	else
	{
		Node* pMove = this->headNode->next;
		Node* pMove_left = this->headNode;
		while (pos > 1)
		{
			pMove_left = pMove;
			pMove = pMove->next;
			pos--;
		}
		pMove_left->next = pMove->next;
		pMove->next = nullptr;
		delete pMove;
        pMove = nullptr;
		this->size--;
	}
}

Find data in linked list

The parameter required by the function is to find the data in the linked list, and then judge whether there is such data in the linked list. If there is such data, it returns true. If not, it returns false. When searching, you also traverse the linked list through a moving pointer. At each step, you can judge whether the data of the node pointed to by pMove is the same as that of the formal parameter num. If you find it, you jump out of the loop. If you don't find it, you continue to look back until pMove reaches the empty position.

bool List::scearch(int num)
{
	Node* pMove = this->headNode;
	while (pMove != nullptr && pMove->data != num)
	{
		pMove = pMove->next;
	}
	if (pMove == nullptr)
		return false;
	else
		return true;
}

Modify data at the specified location

The parameters required by the function are the new data newNum and the specified coordinate pos. For functions with specified position series, I prefer to first judge whether the pos is within the scope of the size attribute, and then directly end the function, and then judge whether the data to be modified is the head node or tail node. If it happens to be, it is to directly call the written function, and then if the modification operation is just not ready, go directly. When pos equals zero, directly modify the data in the header node to newNum; When pos equals size, define a moving pointer pMove, go to the end of the linked list, and then execute pMove - > data = newNum; Finally, the pos is in the range from 1 to size-1. First, define a moving pointer pMove to find the node at the pos position, and then modify it directly. The whole idea is so simple, and the code is not particularly difficult to implement.

void List::changeData(int newNum, int pos)
{
	if (pos<0 || pos>this->size)
		return;
	else if (pos == 0)
		this->headNode->data = newNum;
	else if (pos == this->size)
	{
		Node* pMove = this->headNode;
		while (pMove->next != nullptr)
		{
			pMove = pMove->next;
		}
		pMove->data = newNum;
	}
	else
	{
		Node* pMove = this->headNode;
		while (pos > 1)
		{
			pMove = pMove->next;
			pos--;
		}
		pMove->data = newNum;
	}
}

Main function test

The above member functions have been written, and then test the code I wrote through the main function:

int main()
{
	List myList;
	for (int i = 0; i < 3; i++)
	{
		myList.push_front(i);
	}
	cout << myList.getSize() << endl;
	myList.print_front();
	myList.pop_front();
	cout << "====================" << endl;
	cout << myList.getSize() << endl;
	myList.print_front();
	myList.push_back(99);
	myList.print_front();
	myList.insertByPos(2, 1001);
	cout << myList.getSize() << endl;
	myList.print_front();
	myList.insertByPos(4, 520);
	cout << myList.getSize() << endl;
	myList.print_front();
	myList.pop_back();
	cout << myList.getSize() << endl;
	myList.print_front();
	myList.deleteByPos(2);
	cout << myList.getSize() << endl;
	myList.print_front();
	if (myList.scearch(99))
		cout << "Find the target" << endl;
	else
		cout << "Target not found" << endl;
	cout << "================" << endl;
	if (myList.scearch(1001))
		cout << "Find the target" << endl;
	else
		cout << "Target not found" << endl;
	myList.changeData(88, 3);
	cout << myList.getSize() << endl;
	myList.print_front();
	cout << "===================" << endl;
	myList.changeData(66, 2);
	cout << myList.getSize() << endl;
	myList.print_front();
	return 0;
}

Output results:

3
2       1       0
====================
2
1       0
1       0       99
4
1       0       99      1001
5
1       0       99      1001    520
4
1       0       99      1001
3
1       0       1001
 Target not found
================
Find the target
3
1       0       88
===================
3
1       66      88

Posted by bhavik_thegame on Fri, 15 Oct 2021 20:54:59 -0700