C language tearing double linked list (code and detailed explanation)

Table of contents

Introduction:

 Use C code to achieve (reference for CV masters)

Detailed introduction and explanation of the code (intensive knowledge points)

(May be wrong, big guys give pointers in the comment area) [doge life-saving]

1. Dynamically apply for a node

2. Print (traversing the linked list)

3. Tail plug data

4. Head plug data

5. Header delete data

6. Delete data at the end

7. Find the array (return the address of the searched data)

8. Insert y after the linked list X data

9. Insert y before the linked list X data

10. Change the X value in the linked list to y

11. Delete the node where the X value in the linked list is located

12. Delete a node before the X value in the linked list

13. Delete a node after the X value in the linked list

14. Destruction of the linked list


Introduction:

       First, let's understand what a double-line linked list is:

As the name implies, the double linked list means that the linked list has changed from a one-way chain to a two-way chain. Using this data structure,

We can no longer be limited to operations such as one-way creation and traversal of singly linked lists, which greatly reduces the problems in use.

 A simplified diagram of a doubly linked list is as follows:

aba8670b0ba84fed8a396d2d73d6d6b6.png

5c0855fce268427f9f5b6be1ac68fbba.png

 37b5386f0f464e76ab0223a8c7b2a2e7.png

 Use C code to achieve (reference for CV masters)

     Friends, if you can leave a precious praise , then Thai pants are hot

The following is the entire code which is divided into:

          1. Dynamically apply for a node (return the address of the new node)

          2. Print (traversing the linked list)

          3. Tail plug data

          4. Head plug data

          5. Header delete data

          6. Delete data at the end

          7. Find the array (return the address of the searched data)

          8. Insert y after the linked list X data

          9. Insert y before the linked list X data

        10. Change the X value in the linked list to y

        11. Delete the node where the X value in the linked list is located

        12. Delete a node before the X value in the linked list

        13. Delete a node after the X value in the linked list

        14. Destruction of the linked list

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
typedef int DLTDateType;
typedef struct DListNode
{
    struct DListNode* prove;
    DLTDateType data;
    struct DListNode* next;
}DListNode;



DListNode* BuyDListNode(DLTDateType x)    // 动态申请一个节点
{
    DListNode* newnode = (DListNode*)malloc(sizeof(DListNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    newnode->data = x;
    newnode->next = newnode;
    newnode->prove = newnode;
    return newnode;

}
void DListPrint(DListNode* head)  //打印链表
{
    DListNode* cup = head->next;
    printf("header <—> ");
    while (cup != head)
    {
        printf("%d <—> ", cup->data);
        cup = cup->next;
    }
    printf("header\n");
}
void DListPushBack(DListNode* head, DLTDateType x)  //尾插
{
    DListNode* newnode = BuyDListNode(x);
    DListNode* pro = head->prove;
    pro->next = newnode;
    newnode->prove = pro;
    newnode->next = head;
    head->prove = newnode;
}
void DListPushFront(DListNode* head, DLTDateType x)  //头插
{
    DListNode* newnode = BuyDListNode(x);
    DListNode* next = head->next;
    newnode->next = next;
    newnode->prove = head;
    head->next = newnode;
    next->prove = newnode;    
}
void DListPopFront(DListNode* head)   //头删
{
    assert(head);
    if (head->next == head)
    {
        printf("DEL error :Empty linked lists cannot be deleted");
        return;
    }
    DListNode* first = head->next;
    DListNode* second = first->next;
    head->next = second;
    second->prove = head;
    free(first);
    first = NULL;
}
void DListPopBack(DListNode* head)  //尾删
{
    assert(head);
    if (head->next == head)
    {
        printf("DEL error :Empty linked lists cannot be deleted");
        return;
    }
    DListNode* Headprove = head->prove;
    DListNode* proveProve = Headprove->prove;
    proveProve->next = head;
    head->prove = proveProve;
}
DListNode* DListFind(DListNode* head, DLTDateType x)   //查找
{
    DListNode* cup = head->next;
    while (cup != head)
    {
        //cup = cup->next;
        if (cup->data == x)
        {
            return cup;
        }
        cup = cup->next;
    }
    printf("Not found\n");
    return NULL;
}
void DListInsertAfter(DListNode* head, DLTDateType x, DLTDateType y)   //x位置之后插入y
{
    DListNode* pos = DListFind(head, x);
    DListNode* newnode = BuyDListNode(x);
    newnode->data = y;
    DListNode* next = pos->next;
    next->prove = newnode;
    newnode->next = next;
    newnode->prove = pos;
    pos->next = newnode;
}
void DListInsertBefor(DListNode* head, DLTDateType x, DLTDateType y)   //x位置之前插入y
{

    DListNode* pos = DListFind(head, x);
    DListNode* newnode = BuyDListNode(x);
    newnode->data = y;
    DListNode* prove = pos->prove;
    prove->next = newnode;
    newnode->prove = prove;
    newnode->next = pos;
    pos->prove = newnode;
}
void DListChange(DListNode* head, DLTDateType x, DLTDateType y)  //把链表中的X数据改为y
{
    DListNode* pos = DListFind(head, x);
    assert(pos);
    pos->data = y;  
}
void DListErase(DListNode* head, DLTDateType x)  // 链表删除X位置的值
{
    DListNode* pos = DListFind(head, x);
    assert(pos);
    DListNode* prove = pos->prove;
    DListNode* next = pos->next;
    prove->next = next;
    next->prove = prove;
}
void DListEraseBefore(DListNode* head, DLTDateType x)  // 链表删除X位置之前的值
{
    DListNode* pos = DListFind(head, x);
    assert(pos);
    DListErase(head, pos->prove->data);
}
void DListEraseAfter(DListNode* head, DLTDateType x)  // 链表删除X位置之后的值
{
    DListNode* pos = DListFind(head, x);
    assert(pos);
    DListErase(head, pos->next->data);
}
void DListDestroy(DListNode* head)  // 链表的销毁
{
    DListNode* cup = head->next;
    while (cup != head)
    {
        DListNode* pos = cup;
        cup = cup->next;
        free(pos);
        pos = NULL;
    }
}

Detailed introduction and explanation of the code (intensive knowledge points)

(May be wrong, big guys give pointers in the comment area) [doge life-saving]

1. Dynamically apply for a node

        Apart from anything else, let's go to the code first:

typedef int DLTDateType;    //定义一个类型,方便后续更改链表里面的数据类型
typedef struct DListNode
{
	struct DListNode* prove;  //储存前一个节点的地址
	DLTDateType data;         //储存这个节点的值
	struct DListNode* next;   //储存下一个节点的地址
}DListNode;   //新定义结构体的名字


DListNode* BuyDListNode(DLTDateType x)    // 动态申请一个节点
{
	DListNode* newnode = (DListNode*)malloc(sizeof(DListNode));  //malloc 开辟空间
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;          //设置新空间的初始值
	newnode->next = newnode;    //新节点的next 指向他自己
	newnode->prove = newnode;   //新节点的prove也指向他自己
	return newnode;   //返回新节点的地址

 Code explanation:

  1.  First of all, this code is very readable. Create a new node (convenient for reuse). In the subsequent insertion process, you must often create a new node for insertion, so at the beginning we can first insert it It is a very important engineering project thinking to make it into a function to facilitate code reuse.
  2. Creating a new node is actually applying for a space in the memory, just use malloc
  3. To prevent the problem of wild pointers, the prev and next pointers of each new node created are empty. Then just return the address of this node, because the space of this node is on the heap, and the destruction of the function stack frame will not affect this space .

2. Print (traversing the linked list)

code:

void DListPrint(DListNode* head)  //打印链表
{
	DListNode* cup = head->next;  //设置一个局部变量保存链表表头的位置
	printf("header <—> ");  //  打印连接标志(为了美观)
	while (cup != head)     //遍历列表
	{
		printf("%d <—> ", cup->data);  //打印数据
		cup = cup->next;   //变量自增
	}
	printf("header\n");  //最后换行

Code explanation: 

  1.  In the printing function, we first use a local variable to store the position of the head of the linked list. Because of the existence of the sentinel bit, the head of the code is one bit after the sentinel bit. That is, cup = head->next 
  2. Later we printed the connection symbol   <—> (in order to make the printed linked list more intuitive), which is probably as follows:

    120ab5d02af7477aab25dd0718871918.png

  3. When local variables are self-increasing, use the code  cup = cup->next to    cleverly use the structure to increase the cup

3. Tail plug data

        code:

void DListPushBack(DListNode* head, DLTDateType x)  //尾插数据
{
	DListNode* newnode = BuyDListNode(x);   // 使用函数创建新的节点
	DListNode* pro = head->prove;   //使用局部变量记录尾结点的地址
	pro->next = newnode;  //改变尾结点的 next 指针的指向
	newnode->prove = pro; //连接新节点和尾结点 
	newnode->next = head; //产生新的尾结点
	head->prove = newnode;

Code explanation: 

  1.  When inserting the end, the first thing we think of is to have a node for inserting the end. We use the BuyDListNode( X ) function to apply for a new node in the memory to store the data to be inserted.
  2. After having a new node, the next step is to find the tail node. For the doubly linked list, its advantage is that you can find the tail node directly from the head node in one step, without having to traverse the linked list. The operation time of the computer is greatly saved.
  3. The next step is the most important insertion and connection link.87c8463bcb9b4fac8695104bdd31646c.png
  4.  Use the four lines of code as shown in the figure to complete the steps of insertion and connection


4. Head plug data

void DListPushFront(DListNode* head, DLTDateType x)  //头插数据
{
	DListNode* newnode = BuyDListNode(x);   // 使用函数创建新的节点
	DListNode* next = head->next;   //使用局部变量记录头结点的地址
	newnode->next = next;    //改变新结点的 next 指针的指向
	newnode->prove = head;   //连接新节点和头结点
	head->next = newnode;
	next->prove = newnode;	
}

Code explanation:

  1.  When inserting the end, the first thing we think of is to have a node for inserting the end. We use the BuyDListNode( X ) function to apply for a new node in the memory to store the data to be inserted.
  2. After having a new node, the next step is to find the head node, the head node is at the next position of the sentinel position
  3. The next step is the most important insertion and connection link. See the code for details.

5. Header delete data

code:

void DListPopFront(DListNode* head)   //头删数据
{
	assert(head);  //首先要判定一下传入的head 是不是空指针
	if (head->next == head)  // 判断是不是空链表
	{
		printf("DEL error :Empty linked lists cannot be deleted");//如果是空链表则不能删除
		return;
	}
	DListNode* first = head->next;   //头删数据
	DListNode* second = first->next;
	head->next = second;
	second->prove = head;
	free(first);
	first = NULL;
}

Code explanation:

  1. If you want to delete data at the head, you must first find the head of the linked list, because this is a two-way linked list with sentinel bits, and the head of the linked list can be found directly through the sentinel bits.
  2. After finding it, you must judge whether it is an empty linked list. If it is empty, you will be prompted that the user cannot delete it.
  3. After the judgment is completed, the deletion step can be performed. (change pointer direction, link, delete)

6. Delete data at the end

        code:

void DListPopBack(DListNode* head)  //尾删数据
{
	assert(head);    //首先要判定一下传入的head 是不是空指针
	if (head->next == head)  // 判断是不是空链表
	{
		printf("DEL error :Empty linked lists cannot be deleted");//如果是空链表则不能删除
		return;
	}
	DListNode* Headprove = head->prove;  //尾删数据
	DListNode* proveProve = Headprove->prove;//改变指针的方向
	proveProve->next = head;
	head->prove = proveProve;

Code explanation: 

  1. If you want to delete, you must ensure that there is something in the linked list that can be deleted, so first judge whether it is an empty linked list, and if it is empty, the user will be prompted that it cannot be deleted.
  2.  When deleting data at the end, the most important thing is to find the end node (this step is the same as the end insertion above)
  3. After finding the tail node, delete it.

7. Find the array (return the address of the searched data)

code:

DListNode* DListFind(DListNode* head, DLTDateType x)   //查找链表中的X值,返回该节点的地址
{
	DListNode* cup = head->next;  //利用局部变量来记录链表的表头,方便后面的遍历
	while (cup != head)     //遍历链表
	{
		//cup = cup->next;
		if (cup->data == x)
		{
			return cup;
		}
		cup = cup->next;   //局部变量自增
	}
	printf("Not found\n");
	return NULL;
}


8. Insert y after the linked list X data

code:

void DListInsertAfter(DListNode* head, DLTDateType x, DLTDateType y)   //X位置之后插入y
{
	DListNode* pos = DListFind(head, x);
	DListNode* newnode = BuyDListNode(x);
	newnode->data = y;
	DListNode* next = pos->next;
	next->prove = newnode;
	newnode->next = next;
	newnode->prove = pos;
	pos->next = newnode;
}


9. Insert y before the linked list X data

code:

void DListInsertBefor(DListNode* head, DLTDateType x, DLTDateType y)   //X位置之前插入y
{

	DListNode* pos = DListFind(head, x);
	DListNode* newnode = BuyDListNode(x);
	newnode->data = y;
	DListNode* prove = pos->prove;
	prove->next = newnode;
	newnode->prove = prove;
	newnode->next = pos;
	pos->prove = newnode;
}


10. Change the X value in the linked list to y

code;

DListChange(DListNode* head, DLTDateType x, DLTDateType y)   修改在X位置的值
{
	DListNode* pos = DListFind(head, x);
	assert(pos);
	pos->data = y;  
}


11. Delete the node where the X value in the linked list is located

void DListErase(DListNode* head, DLTDateType x)  // 链表删除pos位置的值
{
	DListNode* pos = DListFind(head, x);
	assert(pos);
	DListNode* prove = pos->prove;
	DListNode* next = pos->next;
	prove->next = next;
	next->prove = prove;
}

12. Delete a node before the X value in the linked list

void DListEraseBefore(DListNode* head, DLTDateType x)  // 链表删除pos位置之前的值
{
	DListNode* pos = DListFind(head, x);
	assert(pos);
	DListErase(head, pos->prove->data);
}

13. Delete a node after the X value in the linked list

void DListEraseAfter(DListNode* head, DLTDateType x)  // 链表删除pos位置之后的值
{
	DListNode* pos = DListFind(head, x);
	assert(pos);
	DListErase(head, pos->next->data);
}

14. Destruction of the linked list

void DListDestroy(DListNode* head)  // 链表的销毁
{
	DListNode* cup = head->next;
	while (cup != head)
	{
		DListNode* pos = cup;
		cup = cup->next;
		free(pos);
		pos = NULL;
	}
}

Guess you like

Origin blog.csdn.net/m0_75215937/article/details/130652742