Learning Chain List Relevance

Catalog

1. What is a linked list

  2. Creating a static single-chain table

  3. Creating dynamic single-chain lists

1. About Initialization

2. About memory allocation:

3. Storage of structural addresses

Establishing Single Chain List by Tail Interpolation

Head Interpolation for Single Chain Table

3. Addition, deletion, examination and alteration of list of chains

1. Increase

2. Delete

3. Check

4. Change

4. Comprehensive implementation of all foundations

What is a chain list? It's probably a continuous thing just by listening to names. The first time I heard the concept of a "chain list" I thought of a section of train boxes.

In the last blog post, we talked about structs. In fact, chain lists are implemented by structs and pointers.

1. What is a linked list

A chain table is a structure for dynamic storage allocation, which is equivalent to the way the structure forms a node by pointer connection, and each node has a precursor node and a successor node (except the first node has no precursor node and the last node has no successor node), which are grouped into a complete ordered structure. The pointer tracking ensures that each item in the list contains information about where to find the next item.

Now I declare a simple structure:

struct A
{
  char firstname[10];  //Define Data Fields

  struct A *next;  //Defines a pointer field to store the address of the succeeding node
};

struct A *head = NULL;  //Header pointer initialized to null

  The related list structure is:

*head is the header pointer, pointing to the header node;* Next is a successor node, which stores the address of the successor node, makes it easy to access and connect to the next node. (This next should be connected to "yan" because they are all in one structure, and you can't just look at it without making a backup.) If you want to indicate that there is no other structure behind it, set the next member pointer to NULL, which means the end of the list.

This distinguishes the head node from the head node:

Head node: A node is attached to the first node of a single-chain list, which has no direct precursor. Its data domain can contain no information and the pointer field points to the address of the first node (the first node). The purpose of a header node is to make the header pointer non-empty for all linked lists, including empty tables.

First node: The node that holds the first valid data.

That is, before the first node, the head node points to the address of the first node.

There must be a reason why the head node exists. So why set the header node?

  • After adding a header node, the address of the header node is saved in the pointer field of the header node. That is, the first data element also has a precursor node, which is no different from other data elements and does not require special processing.
  • When a chain table has no header node, assuming the header is a header pointer to a single-chain table, it should point to the first node, then the header pointer is empty when the single-chain table is an empty table with length n equal to zero. (The criteria for determining an empty table are: head==NULL)

  2. Creating a static single-chain table

  Static lists are simpler than dynamic lists, so we first set up a display of static lists to feel how the lower lists are connected:

This list is static. The memory of all nodes in the program is not requested by us, but is allocated automatically by the system and released automatically when used up.

We can see that there are three main pointer connections between structure and structure in a chain table: *head, *p, *next. The next pointer is stored at the end of the structure to point conveniently to the next structure in the list of chains, which can be connected in line 15 of the code.

So the question is, why set the p-pointer? Is it good to point directly at the head? This is because if you use the head pointer directly, the value of the head pointer will be changed, and the program will not find the beginning of the chain table, so you need to add a p pointer in the middle.

The output from the above code is:

  3. Creating dynamic single-chain lists

One of the features of a chain table is its efficiency and flexibility. Compared with arrays, a chain table makes it easier to delete and insert data and a series of changes. It also makes the rational use of memory space more efficient and more flexible to modify.

So why is using a chain table more efficient in terms of memory space utilization? This is reflected in its allocation of memory when the dynamic chain table is created:

The so-called dynamic chained list requires us to manually request memory (using malloc or new functions) to store nodes, and manually release the memory after completion.

In the dynamic chain table, each node does not have its own name, and the nodes are connected by the pointer. This means that once a node has a pointer disconnect, the following nodes will no longer be retrieved! (broken)

A complete list of structure chains can be roughly divided into three sections: creation, display, and release. Next, let's talk about the most important and complex pieces: creating a chain table

  1. Allocate memory space for each node using malloc();
  2. Place and store the addresses of each node to connect them.
  3. Collect node information.

Top Code:

#include <stdio.h> 
#include <stdlib.h>
struct Stu *create(int n);     //Create Chain List
void print(struct Stu *head);  //Show Chain List
struct Stu{
	int id;
	char name[50];
	struct Stu *next;
};

//Declare Completion
int main()
{
	int n;
	struct Stu *head = NULL;   //Create header pointer, initialize header pointer to NULL
	printf("Enter the number of nodes you want to create:\n");
	scanf("%d",&n);
	head = create(n);     //Quote
	print(head);          //Quote
}

//The upper is the primary function, referencing two custom functions, and this is the definition of the two custom functions
struct Stu *create(int n)
{
	struct Stu *head,*p,*end;   						//Define Head Node, Normal Node, Tail Node 
	head = (struct Stu *)malloc(sizeof(struct Stu)); 	//Request memory for header node 
	end = head;        									//Set an empty table with the same header and tail addresses 
	for(int i=0;i<n;i++)
	{							                    	//Adding data to a chain table using a for loop 
		p = (struct Stu *)malloc(sizeof(struct Stu));   //Request memory space for normal nodes 
		scanf("%d %s",&p->id,p->name);              	//Assigning values to data fields 
		end->next = p;				                	//Point the data field of the previous node to the current node 
		end = p;     				             		//End points to the current node, and final end points to the end node 
	}
	end->next = NULL;                                   //An empty pointer field to the end indicates the end of the chain
	return head;                                        //Return the address of the header node 
}

void print(struct Stu *head)
{
	struct Stu *t = head;
	int j =1;
	t = t -> next;       //Do not print the header node (if you don't understand why you don't print it, go back to the "Difference between header node and header node" above to see)
	while(t != NULL)
	{
		printf("%d\n%d\n%s\n", j, t->id, t->name);
		t = t->next;
		j++;
	}
}

The output is as follows:

  The first is to create a chain table, and the second is to display a chain table. The specific steps can be viewed through code comments, and here are some points to note:

1. About Initialization

When you first set the head, remember to initialize it to NULL.

Another is that when you start creating a chain table, you need to set an empty table, that is, to set the end and end pointer addresses to be the same (end = head).

2. About memory allocation:

There are two main parts of memory allocation in the chain table above, one is the head node, the other is the normal node. It is not difficult to find the form in which memory is allocated:

The pointer name (that is, its address) to the node = (struct structure name*) malloc(sizeof(struct structure name));

Remember to assign an address before you connect the pointer to the node.

If you're not sure, you can check that malloc() has successfully requested memory by checking whether the return value of malloc is NULL. If NULL is returned, no corresponding memory is obtained.

3. Storage of structural addresses:

Address of the first structureStore in head er pointer
Address for each subsequent structureStored in the next pointer member of the previous structure.

Take a look at the core of the code above, which is the part where it creates a chain table:

The tail insertion method establishes a single-chain table:

Establishing a chain table by tail interpolation is a more general operation. Actually, you can see from lines 30 and 31 of the breakpoint that the end pointer and the p pointer move at the same time, which looks like you feel like these two pointers are doing something different and you just don't want to take either one. nonono, or that sentence, the p pointer is used to connect, while the end pointer is mainly used to track the latest node, so when no new node is added, set the next member in the last node to NULL to represent the end of the chain. Therefore, either deleting a breakpoint or swapping the order will result in a broken list with no output.

In a program's for loop, each time p is entered, a new structure is updated, which can be understood as: in the two assignment statements following the scanf statement in the for loop, for the equal sign, the information of the previous node is on the left, and the information of the new node is on the right.

Head interpolation to create a single-chain table:

Comparing with the code of tail insertion, we can see that the difference between head insertion and tail insertion is not big. Since the end node of the head interpolation method is fixed, we do not need to set an additional end pointer to track the end node. At the same time, header insertion also deleted the empty table setting operation of the 25th row of tail insertion, the main difference is still in rows 30 and 31.

3. Addition, deletion, examination and alteration of list of chains

1. Increase

There are three places to insert elements: the head, the middle, and the end, but the insertion is the same:

1) Point the next pointer of the new node to the node after insertion;

2) Point the next pointer of the node before insertion to the insertion node;

Note that the order of 1 and 2 cannot be adjusted!! It must be connected first, then followed. If the order is adjusted, this part of the list after insertion will be lost and the next join operation will not be possible.

Let's design a function to insert a new node at the nth position in the single-chain list.

void ADD(struct Stu *head, int n)     
{    
	struct Stu *p = head,*pr;
	pr = (struct Stu*)malloc(sizeof(struct Stu));  //pr is a pointer to a new insert node

	printf("Please enter the data you want to insert\n");
	scanf("%d %s",&pr->id,pr->name);
	int i = 0;

    while( i<n-1 && p!=NULL )   //Point p at the location where node n-1 will be inserted 
    {          
    	p = p->next;
		i++;
	}   
		pr->next = p->next;   //Point the address of the new node to the address of the next node that will be inserted into the node 
		p->next = pr;        //Point the insert node to the new node 
}

Start with the first node, find the address p of the N-1 node in the list, and insert the nth node after it. When inserting, first point the pointer pr of the new node to the original nth node, then point n-1 node to the new node, that is, complete the insertion operation.

2. Delete

Deleting a node in a chain table is essentially a removal of the node and requires attention to freeing up unused memory space.

1) Remove nodes from the list of chains;

2) Manually release nodes and reclaim the storage space occupied by deleted nodes;

  In fact, the operation of extracting nodes is very simple, that is:

temp->next=temp->next->next;

Let's set up a function to delete the nth node of a single-chain list:

void DELETE(struct Stu *head,int n)  //Delete node at n
{          
	struct  Stu *p = head,*pr;
	int i =0;
	while(i<n-1 && p!=NULL)     //Find n-1 Node
   {      
		p = p->next;  
		i++;
	}
	if(p!=NULL)   //p cannot point to a node after the tail node (n node does not exist)
    {           
	    pr= p->next;   //pr points to the nth node 
		p->next = pr->next;    //Connect to delete the nodes on the left and right sides of the node (ignore this node)
		free(pr);        //Release Delete Node Memory
	} else{
		printf("Node does not exist\n"); 
	}
} 

  You will find that, except for the contents of the last if statement, the preceding operation is similar to the operation code for Add. So in fact, all kinds of operations in the chain table are similar, the main difficulty is just the way they connect (it will be a bit confusing).

3. Check

Looking for a specified node in a chain table usually uses a traversal method: traverse the nodes in the table in turn from the header, and compare the elements to each node's data element until the comparison succeeds or traverses the NULL at the end of the chain table (the search fails).

Next, we constructor to find the node element, where p is the original chain table and elem represents the element being searched:

int selectElem(struct Stu * p,int id)
{
    struct Stu * t=p;  //New pointer t, initialized as header pointer p
    int i=1;
   
    while (t->next)    //Because of the existence of the header node, the judgement in while is t->next
    {
        t=t->next;
        if (t->id==id) 
        {
			printf("yes");  //Indicates that a node containing this element was found
            return i;
        }
        i++;
    }
	printf("no");  //Indicates no find
    return -1;  //The program executes here, indicating that the lookup failed
}

When you find the node you want to find, you can also choose to print out the contents of the node's data field.

Also note that when traversing a chain table with a header node, you need to avoid the impact of the header node on the test data. Therefore, when traversing, you should establish a traversal method that uses the code above to effectively traverse the chain table directly across the header node.

4. Change

The modification of a linked list node simply requires traversing to find the node that stores the element, and then making changes to the data fields in the node.

Still defines the function operation, code above:

void change(struct Stu *head,int n)
{
	struct Stu *p = head;
	int i = 0;
	while(i<n && p!=NULL)   //Point p to the node that needs to be modified 
   {     
		p = p->next;
		i++;
	}
	if(p != NULL)
    {             
	    printf("Please enter the modified value:\n");
	   scanf("%d %s",&p->id,p->name);	
	}else{
		printf("Node does not exist!\n");
	} 
}

4. Comprehensive implementation of all foundations:

(Some of the notes have not yet been noted, so they look a bit rough and you'll see them)

#include <stdio.h> 
#include <stdlib.h>
struct Stu *create(int n);     //Create Chain List
void print(struct Stu *head);  //Show Chain List
int selectElem(struct Stu * p,int id);  //Find Node
typedef struct Stu{
	int id;
	char name[50];
	struct Stu *next;
}BE;

int main()
{
	int n;
	struct Stu *head = NULL;              //Create Header Pointer 
	printf("Enter the number of nodes you want to create:\n");
	scanf("%d",&n);
	head = create(n);
	ADD(head,3);
	DELETE(head,2);
	change(head,3);
	print(head);
	selectElem(head,2);
	
}

void change(struct Stu *head,int n)     
{
	struct Stu *p = head;
	int i = 0;
	while(i<n && p!=NULL)   //Point p to the node that needs to be modified 
   {     
		p = p->next;
		i++;
	}
	if(p != NULL)
    {             
	    printf("Please enter the modified value:\n");
	   scanf("%d %s",&p->id,p->name);	
	}else{
		printf("Node does not exist!\n");
	} 
}

int selectElem(struct Stu * p,int id)
{
    struct Stu * t=p;  //New pointer t, initialized as header pointer p
    int i=1;
   
    while (t->next)    //Because of the existence of the header node, the judgement in while is t->next
    {
        t=t->next;
        if (t->id==id) 
        {
			printf("yes");
            return i;
        }
        i++;
    }
	printf("no");
    return -1;  //The program executes here, indicating that the lookup failed
}

struct Stu *create(int n)
{
	struct Stu *head,*p;   				        		//Define header node, normal node
	head = (struct Stu *)malloc(sizeof(struct Stu)); 	//Request memory for header node 

	for(int i=0;i<n;i++)
	{							                    	//Adding data to a chain table using a for loop 
		p = (struct Stu *)malloc(sizeof(struct Stu));   //Request memory space for normal nodes 
		scanf("%d %s",&p->id,p->name);              	//Assigning values to data fields 
		p->next = head->next;                           //The new node points to the original first node
		head->next = p;                                 //Head node of chain list points to new node
	}
	return head;                                        //Return the address of the header node 
}

void ADD(struct Stu *head, int n)     
{    
	struct Stu *p = head,*pr;
	pr = (struct Stu*)malloc(sizeof(struct Stu));  //pr is a pointer to a new insert node

	printf("Please enter the data you want to insert\n");
	scanf("%d %s",&pr->id,pr->name);
	int i = 0;

    while( i<n-1 && p!=NULL )   //Point p at the location where node n-1 will be inserted 
    {          
    	p = p->next;
		i++;
	}   
		pr->next = p->next;   //Point the address of the new node to the address of the next node that will be inserted into the node 
		p->next = pr;        //Point the insert node to the new node 
}

void DELETE(struct Stu *head,int n)  //Delete node at n
{          
	struct  Stu *p = head,*pr;
	int i =0;
	while(i<n-1 && p!=NULL)     //Find n-1 Node
{      
		p = p->next;  
		i++;
	}
	if(p!=NULL)   //p cannot point to a node after the tail node (n node does not exist)
{           
	    pr= p->next;   //pr points to the nth node 
		p->next = pr->next;    //Connect to delete the nodes on the left and right sides of the node (ignore this node)
		free(pr);        //Release Delete Node Memory
	} else
{
		printf("Node does not exist\n"); 
	}
} 

void print(struct Stu *head)
{
	struct Stu *t = head;
	int j =1;
	t = t->next;       //Do not print header nodes 
	while(t != NULL)
	{
		printf("%d\t%d\t%s\n",j,t->id,t->name);
		t = t->next;
		j++;
	}
}

Chain lists are incredibly attractive (although they can sometimes make you irritable).

It's a bit too large. It will also start with the list of chains (below) to write about the addition and deletion of single-chain lists with headless nodes, the inversion of chains, circular chains, double-chain lists, binary trees and chains, and so on.

Chain listing goes through hundreds of lines of code to achieve different functions, and it's really accomplishing to be a little bit smart and fussy.

Tags: C Algorithm data structure linked list

Posted on Fri, 03 Dec 2021 14:26:08 -0500 by gio2k