Analysis of data structure chain table C/C++

Article directory

What is a linked list

Linked list, as the name implies, is a kind of linear storage structure, which uses "chain" to connect data in series, but unlike the sequential list, the connected data does not need to be a continuous physical address, but uses a pointer to connect.
For example, using linked list to store {1,2,3}, the physical storage state of data is shown in the following figure: data elements are stored randomly, and the storage structure that indicates the logical relationship between data through pointers is linked storage structure.

Features of linked list

It is convenient to add and delete, only the pointer domain of the adjacent nodes needs to be considered, without moving data, and the time complexity is O (1).
The efficiency of random search is low. It needs to traverse nodes one by one according to the pointer. The time complexity is O (n).
It consumes a lot of space, because each node needs to store not only the data itself, but also the pointer field, which is used to store the addresses of the nodes before and after.

Type of linked list

The common types of linked list are mainly divided into single linked list, two-way linked list and circular linked list. The basic operation and implementation of single / double linked list are recorded below.

1, Single chain table

Single chain table, that is, each node contains only one subsequent pointer;

The head node and the tail node of the single chain table are special. The head node is used to record the base address of the chain table, which is the starting point of the chain table traversal. The subsequent pointer of the tail node does not point to any node, but points to a NULL address.

The time complexity of insertion and deletion is O(1), and the time complexity of random lookup is O(n).

Definition of single chain table

Single chain table initialization


Insertion of single chain table


Deletion of single chain table


Search of single chain table

Update of single chain table

Output of single chain table

Complete code

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef struct Node
{
	int data;//Data domain
	struct Node *next;//Pointer domain
}LNode;


LNode* nodeInit(int n)//n represents the number of nodes other than the head node
{
	//Create the head pointer. Don't forget to point to NULL to avoid wild pointer
	LNode *head=NULL;
	//Create the header node and keep the temp pointer pointing to the current node
	LNode *temp=(LNode*)malloc(sizeof(LNode));
	head=temp;//The head pointer points to the head node, which has no data field
	//If you need to assign a value to the head node, you can use head - > data = XXX;

	for(int i=0;i<n;i++)//Apply for nodes other than header nodes
	{
		LNode *node=(LNode*)malloc(sizeof(LNode));
		cout<<"Please enter data: ";

		if(node)//
		{
			cin>>node->data;//Input data field
			node->next=NULL;//Keep the pointer field of the created node pointing to NULL
	
			/*****Establishing the relationship between the new node and its predecessor******/
			temp->next=node;//1. Give the first address of the new node to the pointer field of its predecessor node
			temp=temp->next;//2. Point the temporary pointer to the next node (successor node)
		}
		else
		{
			cout<<"Memory request failed";
		}
	}

	return head;//The return head pointer is convenient for subsequent operation, and plays an index role in the linked list
}

LNode* insertElem(LNode *head, int elem, int add) 
{
    LNode *temp = head;//Assign the head pointer to the temp pointer first
    //First find the last node to insert
    for (int i = 1; i < add; i++)//Here the insertion position refers to the number, not the index value, so i counts from 1
    {
        temp = temp->next;
        if (temp == NULL) {
            cout<<"Invalid insertion position"<<endl;
            return head;
        }
    }
    //Create insertion node c
    LNode *insert = (LNode*)malloc(sizeof(LNode));
    insert->data = elem;
    //Insert node into linked list
    insert->next = temp->next;//The order cannot be wrong. First, update the pointer field of the inserted node, that is, temp - > next
    temp->next = insert;//Then update the pointer field of the precursor node
    return head;
}

//head is the original linked list, and add is the node index to be deleted
LNode *delElem(LNode *head, int add)
 {
    LNode *temp = head;
    //Traverse to the previous node of the deleted node
    for (int i = 1; i < add; i++)
	{
        temp = temp->next;
        if (temp->next == NULL) 
		{
            cout<<"No such node"<<endl;
            return head;
        }
    }
    LNode *del = temp->next;//Set a separate pointer to the deleted node to prevent loss
    temp->next = temp->next->next;//The way to delete a node is to change the pointer field of the previous node
    free(del);//Release the node manually to prevent memory leakage
    return head;
}


void display(LNode *p) //Just pass in the chain header pointer
{
	LNode *temp =p;//Point the temp pointer back to the head node
	//The output statement is executed as long as the next of the node to which the temp pointer points is not Null.
	while (temp->next)
	{
		temp = temp->next;
		cout<<temp->data;
	}
	cout<<endl;
}

//p is the original list, and elem represents the searched element
int selectElem(LNode * p,int elem){
//Create a new pointer t and initialize it as the head pointer p
    LNode *temp=p;
    int i=1;
    
    while (temp->next) {
        temp=temp->next;
        if (temp->data==elem)
		{
            return i;//Return to node i
        }
        i++;
    }
    //When the program is executed here, it means that the search fails
    return -1;
}

//Update function, where add represents the position of the change node in the linked list, and newElem is the value of the new data field
LNode *amendElem(LNode * p,int add,int newElem){
    LNode * temp=p;
    temp=temp->next;//Before traversal, temp points to the primary node
    //Traverse to the node to be updated
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    temp->data=newElem;
    return p;
}

int main()
{
	LNode *p = NULL;
	p=nodeInit(5);
	cout<<"The original list is:"<<endl;
	display(p);//Output original list

	cout<<"Insert element 5 at position 4"<<endl;
    p = insertElem(p, 5, 4);
    display(p);

	cout<<"Delete element 3"<<endl;
    p = delElem(p, 3);
    display(p);

	cout<<"Find element 2 at"<<endl;
    int address = selectElem(p, 2);
    if (address == -1) {
        printf("There is no such element");
    }
    else
	{
		cout<<"The location of element 2 is:"<<address<<endl;
    }

	cout<<"Change the data on position 3 to 7"<<endl;
    p = amendElem(p, 3, 7);
    display(p);

	return 0;
}

-----------------

2, Double linked list

Each node in a two-way linked list has two direction pointers,
• subsequent pointer: points to the subsequent node,
• precursor pointer: the node pointing to the precursor.
There are also two special nodes in the two-way linked list. The precursor pointer of the first node and the successor pointer of the tail node point to NULL address.

Definition of double linked list

Compared with the single linked list, each node of the two-way linked list has an additional pointer field for pointing to the direct precursor. Therefore, we can create double linked list on the basis of single linked list.

It should be noted that in the process of creating a double linked list, different from a single linked list, each new node must establish two connections with its predecessor nodes, namely:

• point the prior pointer of the new node to the direct predecessor node: node - > prior = temp;
• point the next pointer of the direct precursor node to the new node: temp - > next = node;

Bidirectional list initialization


Get link length

Insert node (not tail)


Add (insert) nodes at the end


Deletion of double linked list

Modification of linked list

Get node data / location / precursor

Output of double linked list

Complete code

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef struct Node
{	
	struct Node *prior;//Precursor pointer
	int data;//Data domain
	struct Node *next;//Successor pointer
}LNode;


LNode* nodeInit(int n)//n represents the number of nodes other than the head node
{
	//Create the head pointer. Don't forget to point to NULL to avoid wild pointer
	LNode *head=NULL;
	//Create the header node and keep the temp pointer pointing to the current node
	LNode *temp=(LNode*)malloc(sizeof(LNode));
	head=temp;//The head pointer points to the head node, which has no data field

	head->prior=NULL;
	head->next=NULL;
	//If you need to assign a value to the head node, you can use head - > data = XXX;

	for(int i=0;i<n;i++)//Apply for nodes other than header nodes
	{
		LNode *node=(LNode*)malloc(sizeof(LNode));
		cout<<"Please enter data: ";

		if(node)
		{
			cin>>node->data;//Input data field
			node->next=NULL;//Keep the pointer field of the created node pointing to NULL

			/*****Establishing the relationship between the new node and its predecessor******/
			node->prior=temp;//The prior of the new node is the first address of the previous node, temp
			temp->next=node;//1. Give the first address of the new node to the pointer field of its predecessor node
			temp=temp->next;//2. Point the temporary pointer to the next node (successor node)
		}
		else
		{
			cout<<"Memory request failed";
		}
	}

	return head;//The return head pointer is convenient for subsequent operation, and plays an index role in the linked list
}



//Get the length of the linked list (excluding the head node)
int getlength(LNode *head)
{
	LNode *temp = head;
	int len = 0;
	while(temp->next)
	{
		temp = temp->next;
		len++;	
	}
	return len;
}


LNode* insertElem(LNode *head, int elem, int add) //Non tail insertion node
{
    LNode *temp = head;//Assign the head pointer to the temp pointer first
    //First find the last node to insert
	//To find this node, you need to point the pointer of temp to the first node of the header node, temp = temp - > next;
    for (int i = 1; i < add; i++)//Here, the insertion position refers to the number, not the index value, so i counts from 1, and temp points to the previous node of the position to be inserted
    {
        temp = temp->next;
        if (temp == NULL) {
            cout<<"Invalid insertion position"<<endl;
            return head;
        }
    }
    //Create insertion node c
    LNode *insert = (LNode*)malloc(sizeof(LNode));
    insert->data = elem;
    //Insert node into linked list
    insert->next = temp->next;//The order cannot be wrong. First, update the pointer field of the inserted node, that is, temp - > next
	insert->prior=temp;//The precursor pointer points to the previous node
    temp->next = insert;//Then update the pointer field of the precursor node
    return head;
}

//Add (insert) node at the end
LNode* insertEnd(LNode *head, int elem)
{
	LNode *temp=head;
	LNode *node=(LNode*)malloc(sizeof(LNode));//Create a tail node

	while(temp->next)//Traverse to tail node
	{
		temp=temp->next;
	}

	node->next=NULL;
	node->prior=temp;
	node->data=elem;
	temp->next=node;

	return head;

}

//Delete Vertex
LNode *delElem(LNode *head, int add)
 {
    LNode *temp = head;
    //Traverse to the previous node of the deleted node
    for (int i = 1; i < add; i++)//Use traversal to find the previous node of the node (excluding the header node)
	{
        temp = temp->next;
        if (temp->next == NULL) 
		{
            cout<<"No such node"<<endl;
            return head;
        }
    }

	if(add==getlength(head))//If the deleted node is a tail node
	{
		cout<<"The list after deleting the tail node is:";
		LNode *del = temp->next;//Set a separate pointer to the deleted node to prevent loss
		temp->next=NULL;

		free(del);//Release the node manually to prevent memory leakage
	}
	else//If the deleted node is a general node
	{
		LNode *del = temp->next;//Set a separate pointer to the deleted node to prevent loss
		temp->next = temp->next->next;//The way to delete a node is to change the pointer field of the previous node
		temp->next->prior=temp;
		free(del);//Release the node manually to prevent memory leakage
	}

    return head;
}


//Modify node data
LNode *editElem(LNode *head, int n, int newdata)
 {
    LNode *temp = head;
	temp=temp->next;//Temp first points to the first node except the header node. If you delete this statement, temp will point to the header node at the beginning

    for (int i = 1; i < n; i++)//Use traversal to find the node. At this time, temp points to the node
	{
        temp = temp->next;
        if (temp->next == NULL) 
		{
            cout<<"No such node"<<endl;
            return head;
        }
    }
	temp->data=newdata;

	return head;
}

//Get the node at the specified location. If you get the location of the specified element, add if judgment to return n during traversal
int getElem(LNode *head, int n)
 {
    LNode *temp = head;
    for (int i = 1; i <= n; i++)//Another method of traversal, which you can handle flexibly according to your preference
	{
        temp = temp->next;
		//If (Temp - > data = = XXX, return n) plus this statement can be modified to return the location of the specified element
        if (temp->next == NULL) 
		{
            cout<<"No such node"<<endl;
            return 0;
        }
    }

	return temp->data;
	//Return temp - > prior - > data; you can obtain the data of the precursor node of the node and the advantages of the two-way linked list
}

//Double linked list reversal
LNode *Reverse(LNode *head)
{
	LNode *temp=head;//temp pointer is not necessary, just habit
	LNode *current=temp->next;
	LNode *pre=NULL;
	LNode *pnext=NULL;
	while(current)
	{
        //Set the pointer separately to keep the successor node,
		//You cannot use current=current->next because you need to point it to the pre precursor below
        pnext = current -> next;
        //New follow-up to the precursor to reverse
        current -> next = pre;
		current->prior=pnext;
 
        //Move the current node back
        pre = current;
        current = pnext;
	}
	current=head;//Point the head pointer to current and return current as the new head pointer
	current->next=pre;
	current->prior=NULL;//NULL initialization of head node precursor pointer
	return current;
}

//Output linked list
void display(LNode *head) //Just pass in the chain header pointer
{
	LNode *temp =head;//Point the temp pointer back to the head node
	//Execute the output statement as long as the next of the node to which the temp pointer points is not Null
	while (temp->next)
	{
		temp = temp->next;
		cout<<temp->data;
	}
	cout<<endl;
}

int main()
{
	LNode *p = NULL;
	p=nodeInit(5);
	cout<<"The original list is:";
	display(p);//Output original list
	cout<<"The length of the list is: "<<getlength(p)<<endl;

	//Non tail insertion node
	cout<<"Insert 8 in the first position:";
	p=insertElem(p,8,1);
	display(p);

	//Double linked list inversion
	p=Reverse(p);
	cout<<"After the list is reversed, it is: ";
	display(p);

	//Tail insertion node
	cout<<"Insert 0 at the end:";
	p=insertEnd(p,0);
	display(p);

    //Delete node (including tail)
	p=delElem(p,7);
	display(p);
	
	//Modify node data
	cout<<"Modify the data of node 1 to 5:";
	p=editElem(p,1,5);
	display(p);

	//Get node data
	cout<<"Obtain the data of the third node as follows:"<<getElem(p,3)<<endl;


	return 0;
}

-----------------

Linked list inversion

Inversion of single chain table

Inversion of double linked list

Summary

The author is not only a professional, but also a car electronic practitioner. He has a simple understanding of the basic operation and implementation of single / double linked list. It is recorded in the memory of the public. It is also recorded in the official account of Xiao Bai (review at any time): the book of intelligent driving software is for reference only. If there is any doubt, please discuss with the author.

Published 1 original article, praised 0 and visited 5
Private letter follow

Posted on Wed, 11 Mar 2020 07:01:10 -0400 by karan23424