Conceptual understanding of one-way chain table and implementation of common interfaces

Preface

Linear tables in data structure are the beginning of the data structure foundation, and also the content that we need to implement many times in the follow-up study. The common interfaces need to be mastered. This paper will explain the knowledge content of chain tables in linear tables from the concept nature, concept illustration, interface code and so on.

1. Linear tables (review)

1.1 Concepts of Linear Tables & Understanding (Review)

Definition: Linear table is the most basic, simple and common data structure. linear list is a kind of data structure, and a linear table is a finite sequence of n data elements with the same characteristics.

The relationship between data elements in a linear table is one-to-one, that is, all data elements except the first and last are end-to-end (note that this statement only applies to most linear tables, not all).

Personal understanding: linear list is a limited sequence of n data elements with the same characteristics. Linear table is a widely used data structure in practice. Common linear tables are sequence table, chain table, stack, queue, string...

PS: Linear tables are logically linear, meaning that if we use a line to connect elements together, they can be pulled into a straight line, or a continuous line. But they are not necessarily continuous in physical structure. When stored physically, linear tables are usually stored as arrays and chains.

Illustration of 1.2 Linear Table (Review)

Illustration:
1.1 Linear Sensory Cognition

1.2 Chain Table Structure Display (Logical Structure)

The existence of the joints in the diagram is the logical structure. We draw the arrows to visually connect the data into a straight line, but in fact, the chain table may not be stored in memory as neatly as in the following figure

1.3 Chain List Structural Display (Physical Structures) Map address values are used for example only and are not valid real data

1.4 Order Table

2. Chain List

2.1 Chain List Concept-Structure

Concepts: Chain table is a physical storage structure that is not continuous or sequential. The logical order of data elements is achieved by the order of pointer links in the chain table.

Structure:
(1) Chain structures are continuous in logical structure, but not necessarily in physical structure;
(2) Nodes in memory are generally requested from the heap;
(3) The space requested from the heap is allocated according to a certain strategy. The space requested twice may be contiguous or may not be contiguous (with malloc and realloc dynamic memory functions implemented)

Illustration:

Classification of 2.2 Chain Lists

In practice, there are many kinds of chain table structure, the following are the types of chain table structure that we will often encounter in future learning:

1. One-way Chain List

(2) Bidirectional Chain List
(3) Unheaded single-chain list (commonly used)

(4) Leading Chain List

Circular single-chain list
Leading bidirectional circular chain list (commonly used)
............ (many types are also used)

Implementation of 2.3 Chain List Interface

We need to implement a series of interfaces (functions) in a chain table, which need to be implemented and changed in other kinds of chain tables, queues and so on, so the implementation of interfaces is very important.

Here, for ease of understanding, we use headless, one-way, non-circular chained lists to implement common interfaces

First, we define the node structure:

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;//Stores data for the current node
	struct SListNode* next;//Pointer to the next node;
} SLTNode;


Illustration:

2.3.1 Dynamically requesting a node

SLTNode* BuySListNode(SLTDataType x)//Create a new node and return its address value
{
	SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
	if (node == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	node->data = x;
	node->next = NULL;

	return node;
}

Illustration:

Printing of 2.3.2 Single Chain List

void SListPrint(SLTNode* phead)//Print the contents of each node
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

Illustration:

End Interpolation of 2.3.3 Single Chain List

Correct code:

void SListPushBack(SLTNode** pphead, SLTDataType x)//End Insert:
{
	assert(pphead);

	if (*pphead == NULL)
	{
		SLTNode* newnode = BuySListNode(x);
		*pphead = newnode;
	}
	else
	{
		// Find the tail
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		SLTNode* newnode = BuySListNode(x);
		tail->next = newnode;
	}
}

Error code:

void SListPushBack(SLTNode** pphead, SLTDataType x)//End Insert:
{
	assert(pphead);
	assert(*pphead);

	while ((*pphead)->next != NULL)
	{
		*pphead = (*pphead)->next;
	}

	SLTNode* new = (SLTNode*)malloc(sizeof(SLTNode));

	(*pphead)->next = new;
	new->next = NULL;

}

Analysis: Although I have implemented the tail insertion function here, at the end of the tail insertion, I can no longer find the content of the pre-insertion chain table, because the head pointer to the chain table has moved, and the chain form one-way chain table can only query the content after the current node, it can not find the content backwards, so such code will result in the loss of the content of the chain table.

Illustration:


Head Interpolation for 2.3.4 Single Chain Lists

void SListPushFront(SLTNode** pphead, SLTDataType x)//Head plug
{
	assert(pphead);
	SLTNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

Illustration:

Tail deletion of 2.3.5 one-way chain list

void SListPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* prev = NULL;
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}

		free(tail);
		prev->next = NULL;
	}
}

Analysis 1: Here we need to consider two possibilities when implementing the tailing function, the first is that the chain table is empty, the second is that the chain table is normal.

Analysis 2: Secondly, when we implement the tail deletion function, we need to find the endpoint and save the address of the previous node of the endpoint, because when we delete the endpoint, the previous node becomes a new endpoint, and we need to cover the pointer field of its node with NULL;

Illustration:


2.3.6 Header Deletion of One-way Chain Lists

void SListPopFront(SLTNode** pphead)//Head deletion
{
	assert(pphead);
	assert(*pphead);

	SLTNode* next = (*pphead)->next;
	free(*pphead);
	(*pphead) = next;
}

Analyze code for another method:

void SListPopFront(SLTNode** pphead)//Head deletion
{
	assert(pphead);
	assert(*pphead);

	SLTNode* cur = *pphead;
	SLTNode* next = (*pphead)->next;
	free(cur);
	*pphead = next;
	
}

Analysis: This is not a thorough understanding of the free() function. The function of the free function is to release the space pointed to by the current parameter pointer, but the parameter pointer can still execute the released space address, so such code will appear

Illustration:


Lookup of 2.3.7 Single Chain List

True code:

SLTNode* SListFind(SLTNode* phead, SLTDataType x)//lookup
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

Error code:

SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);

	SLTNode* cur = phead;
	while (cur->data != x)
	{
		cur = cur->next;
	}

	return cur;
}

Analysis: This ignores the case that if the element we are looking for is not used in the current list, then this interface will return NULL.

Illustration:

Insertion of 2.3.8 Single Chain List after pos position

void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

Illustration:

2.3.9 Sequential Table Value after deleting pos position

void SListEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);//Preventive is the end position:

	SLTNode* next = pos->next;
	pos->next = next->next;

	free(next);
	next = NULL;
}

2.4 Comparison of Sequential and Chain Tables

DifferenceSequence tablelinked list
storage spacePhysically ContinuousLogically continuous, physically not necessarily continuous
Random AccessSupport O(1)O(N) not supported
Insert or delete elements anywhereElements can be moved arbitrarily, but inefficient O(N)Simply modify the pointer pointer
insertDynamic Sequential Table, Use Dynamic Memory Function for Expansion when Out of SpaceConcept of unused capacity
Application ScenariosElement efficient storage, frequent accessInsert and delete frequently anywhere
Cache utilizationhighlow

summary

(1) Chain table is a physical storage structure that is not continuous or sequential. The logical order of data elements is achieved by the order of pointer links in the chain table.

(2) Chain structure is continuous in logical structure, but not necessarily in physical structure;

(3) When we implement various interfaces of one-way chained list, we should learn to consider many situations, such as empty chained list.

That's my personal understanding of this approach

If there are any mistakes in the above content, please ask all the big guys to give us some advice [Bye you guys] [Bye you guys]

Tags: C Programming data structure linked list

Posted on Thu, 16 Sep 2021 14:05:23 -0400 by ExpertAlmost