Data structure - headed two-way circular linked list


1. Head node

What is the purpose of setting the head node in a linked list?

identifies the linked list: the head node is a special node of the linked list, and its existence can clearly identify that this is a linked list. In a linked list, the head node usuallydoes not contain any data. Its main function is to serve as the entry< of the linked list. /span> Improve efficiency: The existence of the head node can improve the efficiency of linked list operations. Since the head node is the first node of the linked list, we do not need to worry about the moving direction of the pointer when traversing the linked list. At the same time, due to the special position of the head node in the linked list, when you need to access the first element of the linked list, you can obtain it by directly accessing the head node without traversing the entire linked list.
Simplified operations: The existence of the head node can simplify the operations of the linked list. For example, when we need to traverse the entire linked list, we only need to start from the head node, without caring about the starting position of the linked list. At the same time, the existence of the head node also makes operations such as inserting or deleting nodes at the end of the linked list more convenient. makes the operation of the linked list more convenient.

Insert image description here

2. Double linked list

1·Concept and structure of doubly linked list

Concept: A doubly linked list is a physical storage structure that is non-continuous and non-sequential. The logical order of data elements is achieved through the bidirectional link order of pointers in the linked list.

Structure diagram:
Insert image description here

2.Compared with singly linked list

Bidirectionality: The double linked list supports storing the pointers of the predecessor node and successor node on each node, so that it can be stored on any node. Easily find its predecessor and successor nodes. However, a singly linked list can only find the next node or previous node of a specific node by traversing the entire linked list, which is less efficient. Insertion and deletion operations are more efficient: Since doubly linked lists support bidirectional links, during insertion and deletion operations, doubly linked lists only need to readjust the relevant pointers, unlike singly linked lists. Need to traverse the entire linked list. This makes insertion and deletion operations in doubly linked lists more efficient.

3. Circular linked list

1.About circular linked list

A circular linked list is a special type of linked list in which the last node points to the first node, which is the starting node. The start node serves as a reference point for the beginning of the list.

(1) When traversing, you can start from any node and traverse the list forward or backward in any direction until you reach the same node where you started.
(2) The circular linked list has no beginning or end.
(3) In a circular linked list, the address part of the last node saves the address of the first node, thus forming a circular chain structure.

(4).Structure diagram:
Insert image description here

2. Advantages of circular linked list

(1) Memory utilization is one of the common advantages of circular linked lists
Unlike linear data structures, circular linked lists allow people to use memory efficiently because the size of the linked list increases dynamically or reduced so no memory is wasted. Additionally, there is no need to pre-allocate memory.
(2) Implementation
Due to the ability to utilize memory and ease of data manipulation, linear data structures like stacks and queues can often be easily implemented using linked lists.
(3) Easy data operation
Can effectively handle the insertion and deletion of circular linked lists without the need to reconstruct the linked list. There is no need to move the element after inserting or deleting it, just update the address present in the next pointer.

4. Taking the lead in two-way circular linked list

1. Take the lead in two-way circular linked list

The structure is the most complex and is generally used to store data separately. The linked list data structures used in practice are all headed bidirectional circular linked lists. In addition, although this structure is complex, after using the code to implement it, you will find that the structure will bring many advantages, and the implementation will be simple. We will know it later when we implement the code.

2. Structure diagram

Insert image description here

3. Realize

Ideas:
(1) Use structures to store data and pointers (structures can store different types of data)
(2) Through malloc Function expansion
(3) Implementation through multiple conditions
(4) We implement initialization, printing, expansion, tail insertion, head insertion and other functions
Framework:
Creation of structure, some definitions, etc.
List.h

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;

typedef struct ListNode
{
    
    
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}ListNode;

Test.c

void Test() {
    
    
	ListNode* plist = ListInit()初始化,头结点不存储数据;
	}
int main() {
    
    
	Test();
	return 0;
}

Function implementation:
(1) Expansion function:
Return value: a structure pointer
Parameters: The passed data
is expanded through the malloc function, and the expanded pointer is set to empty and the passed data is stored
Code:

ListNode* BuyListNode(LTDataType x) {
    
    //扩容
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));//扩容
	newnode->data = x;//存储数据
	newnode->next = NULL;//指针置空
	newnode->prev = NULL;
	return newnode;//返回指针
}

(2) Initialization function
We start by initializing a head node (no data is stored)
Return: a pointer (our head node dot)
Code:

ListNode* ListInit() {
    
    //初始化
	ListNode* phead = BuyListNode(0);//第一个数据不打印
	phead->next = phead;//只有一个头结点,因为是双向循环链表,自己连接自己
	phead->prev = phead;
	return phead;
}

How to:
Insert image description here
Stamp function
Daigo:

void ListPrint(ListNode* phead) {
    
    
	assert(phead);//判断是否为空
	//初始条件
	ListNode* cat = phead->next;//打印出头结点next指向的结构体开始
	//结束条件
	while (cat!= phead)//当打印完一次后就会遇上同结点,此时结束打印
	{
    
    
		printf("%d ", cat->data);
		//迭代条件
		cat = cat->next;
	}
	printf("\n");
}

(3) Tail insertion function
We want to insert the end of a data into it
Step 1: Find the end of the linked list, we It can be found through the head node
Step 2: We redirect the next of the structure at the end to point to the structure inserted at the end, and then point the prev of the structure inserted at the end to the end. The structure at the end, then point the next of the structure inserted at the end to the head node, and then point the perv of the head node to the structure inserted at the end
before inserting :
Insert image description here
After insertion:
Insert image description here
Code:

void ListPushBack(ListNode* phead, LTDataType x) {
    
    //尾插
	assert(phead);//判断是否为空
	ListNode* newnode = BuyListNode(x);//扩容
	ListNode* cat = phead->prev;//找到尾结点并保存
	//重新连接
	cat->next = newnode;
	newnode->prev = cat;
	phead->prev = newnode;
	newnode->next = phead;
}

检查:
tail 1 , 2 , 3

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);

Run result:
Insert image description here
(4) Head insertion function
We want to insert a data tail into it
Step 1: Find the first point where data is stored through the head node
Step 2: We re-insert the prev pointer of the structure at the node where data is stored into the head. structure, then point the next of the structure inserted into the head to the first structure that stores data, then point the prtv of the structure inserted into the head to the head node, and then point the next of the head node Point to the inserted structure

Before:
Insert image description here
After:
Insert image description here
Before:

void ListPushFront(ListNode* phead, LTDataType x) {
    
    //头插
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	ListNode* cat = phead->next;//找到头结点并保存
	//重新连接
	cat->prev = newnode;
	newnode->next = cat;
	phead->next = newnode;
	newnode->prev = phead;
}

examine:

头插 0
ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);

Run result:
Insert image description here
(5) Head deletion function
We want to delete the first data
Step one: Find the first node that stores data through the head node, and then find the second node that stores data through the first node that stores data
Step two: Release the first node that stores data, then point the prev of the second node that stores data to the head node, and then point the next node of the head node to the second node that stores data
Before deletion:
Insert image description here
After deletion:
Insert image description here

Code:

void ListPopFront(ListNode* phead) {
    
    //头删
	assert(phead);
	assert(phead->next != phead);//
	ListNode* cat = phead->next->next;
	//通过第一个存储结点找到第二个存储的结点并保存
	free(phead->next);//释放掉
	phead->next = NULL;//并置空
	//重新连接
	cat->prev = phead;
	phead->next = cat;
	
}

Check:
Delete one data in the header

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);
ListPopFront(plist);

operation result:

Insert image description here
(6) Tail deletion function
We delete the last node
Step 1: Find the last node through the head node , and then find the penultimate node through the last node
Step 2: Release the last node, and then point the next of the penultimate node to the head node , and then point the prev of the head node to the penultimate node
Before deletion:
Insert image description here
After deletion:
Insert image description here
Check
Delete a piece of data

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);
ListPopFront(plist);
ListPopBack(plist);
ListPrint(plist);

operation result:
Insert image description here

5. Code overview

List.h:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;

typedef struct ListNode
{
    
    
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}ListNode;

ListNode* ListInit();//初始化
void ListDestory(ListNode* phead);//清空
void ListPrint(ListNode* phead);//打印

void ListPushBack(ListNode* phead, LTDataType x);//尾插
void ListPushFront(ListNode* phead, LTDataType x);//头插
void ListPopFront(ListNode* phead);//头删
void ListPopBack(ListNode* phead);//尾删

List.c:

#define _CRT_SECURE_NO_WARNINGS
#include"List.h"

ListNode* BuyListNode(LTDataType x) {
    
    //扩容
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

ListNode* ListInit() {
    
    //初始化
	ListNode* phead = BuyListNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

void ListPrint(ListNode* phead) {
    
    
	assert(phead);
	//初始条件
	ListNode* cat = phead->next;
	//结束条件
	while (cat!= phead)
	{
    
    
		printf("%d ", cat->data);
		//迭代条件
		cat = cat->next;
	}
	printf("\n");
}
void ListPushBack(ListNode* phead, LTDataType x) {
    
    //尾插
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	ListNode* cat = phead->prev;
	cat->next = newnode;
	newnode->prev = cat;
	phead->prev = newnode;
	newnode->next = phead;
}
void ListPushFront(ListNode* phead, LTDataType x) {
    
    //头插
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	ListNode* cat = phead->next;
	cat->prev = newnode;
	newnode->next = cat;
	phead->next = newnode;
	newnode->prev = phead;
}
void ListPopFront(ListNode* phead) {
    
    //头删
	assert(phead);
	assert(phead->next != phead);
	ListNode* cat = phead->next->next;
	free(phead->next);
	phead->next = NULL;
	cat->prev = phead;
	phead->next = cat;
	
}
void ListPopBack(ListNode* phead) {
    
    //尾删
	assert(phead);
	assert(phead->prev != phead);
	ListNode* cat = phead->prev->prev;
	free(phead->prev);
	phead->prev = NULL;
	cat->next = phead;
	phead->prev = cat;
}

Test.c

void Test() {
    
    
	ListNode* plist = ListInit();
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushFront(plist, 0);
	ListPopFront(plist);
	ListPopBack(plist);
	ListPrint(plist);
	}

	int main() {
    
    
	Test();
	return 0;
}

The above is all the code
There are also some interface functions such as checking and correction that have not been implemented. If you are interested, you can try it

The above is what I shared. If there are any mistakes, please leave a message in the comment area.
Finally, thank you everyone for watching!

Guess you like

Origin blog.csdn.net/2302_79539362/article/details/134750330