The strongest data structure in history----the implementation of doubly circular linked list (with sentinel bit)

1. The basic structure of a doubly linked list

Icon:

image-20220322193710211

2. Implementation of the basic structure of a doubly linked list

Code:

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType data;//存储的数据
	struct ListNode* next;//存储下一个节点的地址
	struct ListNode* prev;//存储上一个节点的地址
}ListNode;

3. Initialization of doubly linked list

Icon:

image-20220322194941041

Code:

The first one: pass the second-level pointer

void ListInit(ListNode** phead);//初始化函数的声明
void ListInit(ListNode** phead)//为什么要传二级指针,因为改变的是结构体的指针,所以要传结构体的指针
{
	assert(phead);
	*phead = BuyListNode(-1);//此处是开辟一个哨兵位的节点,存储的是无效数据,-1也是随便给的
	(*phead)->next = (*phead);
	(*phead)->prev = (*phead);
    //这两行代码主要是使哨兵位的next指针和prev指针自己指向自己,形成双向循环结构
}
//下面是main函数中调用初始化函数的地方,为了方便理解二级指针
int main()
{
	ListNode*phead = NULL;//初始化之后,phead就会指向哨兵位,即NULL发生了改变,即改变的是结构体的指针,所以要传二级指针
	ListNode(&phead);
	return 0;
}

The second: do not pass secondary pointers

ListNode* ListInit(ListNode* phead);//初始化函数的声明
ListNode* ListInit()//此处为什么不传二级指针,因为在函数中会将开辟的哨兵位的地址作为返回值返回
{
	ListNode*phead = NULL;
	phead = BuyListNode(-1);//此处是开辟一个哨兵位的节点,存储的是无效数据,-1也是随便给的
	phead->next = phead;
	phead->prev = phead;
    //这两行代码主要是使哨兵位的next指针和prev指针自己指向自己,形成双向循环结构
}
int main()
{
	ListNode*phead = ListInit();
	return 0;
}

4. Tail insertion of doubly linked list

Icon:

image-20220322201340163

Code:

void ListPushBack(ListNode* phead, LTDataType x)
{
	assert(phead);//哨兵位不可为空
	ListNode* newnode = BuyListNode(x);
	ListNode* tail = phead->prev;
	tail->next = newnode;//(1)
	newnode->prev = tail;//(2)
	newnode->next = phead;//(3)
	phead->prev = newnode;//(4)
}

5. Tail deletion of doubly linked list

Icon:

image-20220322202619685

Code:

void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(phead->next == phead);//链表为空
	ListNode* tail = phead->prev;
	ListNode* tailPrev = tail->prev;

	free(tail);
	tail = NULL;

	tailPrev->next = phead;//(1)
	phead->prev = tailPrev;//(2)
}

6. The header of the doubly linked list

Icon:

image-20220322203851599

Code:

void ListPushFront(ListNode* phead,LTDataType x)
{
	assert(phead);
	ListNode* next = phead->next;
	ListNode* newnode = BuyListNode(x);
	phead->next = newnode;//(1)
	newnode->prev = phead;//(2)

	next->prev = newnode;//(3)
	newnode->next = next;//(4)
}

7. Delete the head of the doubly linked list

Icon:

image-20220322211111550

Code:

void ListPopFront(ListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	ListNode* nextNext = phead->next->next;
	free(phead->next);
	phead->next = nextNext;//(1)
	nextNext->prev = phead;//(2)
}

8. Printing of doubly linked list

Code:

void ListPrint(ListNode* phead)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)//当cur = phead的时候说明已经遍历完一遍了
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

9. Search for elements of doubly linked list

Code:

ListNode*ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur!=phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

Note: Why set cur to phead->next at the very beginning?

1. Because the phead is not valid data stored in the sentinel bit, it cannot be searched from this.
2. At the same time, phead is used as the termination condition of the search. It cannot start from this element. If the search starts from this element, the search will stop at the beginning.

10. Delete a specific element of a doubly linked list

Icon:

image-20220322215420324

Code:

void ListErase(ListNode* pos)
{
    assert(pos);
	ListNode* next = pos->next;
    ListNode* prev = pos->prev;
    free(pos);
    pos = NULL;//此处可以置空也可以不置空,因为pos只是函数中的局部变量
    prev->next = next;//(1)
    next->prev = prev;//(2)
}

CamelCase naming rules:

  1. Capitalize all words in function and type names
  2. Variables: first word lowercase, subsequent words capitalized

11. Pre-insertion of specific elements in a doubly linked list

Icon:

image-20220322220923174

Code:

void ListInsertBefore(ListNode* phead, ListNode* pos, LTDataType x)
{
	assert(pos);
    ListNode* newnode = BuyListNode(x);
	ListNode* prev = pos->prev;
	prev->next = newnode;//(1)
	newnode->prev = prev;//(2)
	pos->prev = newnode;//(3)
	newnode->next = pos;//(4)
}

12. Destruction of doubly linked list

Icon:

image-20220323165823070

Code:

The first one: If the second-level pointer is passed, the space of the sentinel bit will be released at this time.

void ListDestory(ListNode** phead)
{
	assert(phead);
	ListNode* cur = (*phead)->next;
	while (cur!=(*phead))//结束条件就是不等于头节点
	{
		ListNode* next = cur->next;//存储当前释放节点的下一个节点的地址
		free(cur);//释放当前节点
		cur = next;//将节点向后推移
	}
	free(*phead);//释放哨兵位节点
	*phead = NULL;//防止内存泄漏
}

The second: if the secondary pointer is not passed, the space of the sentinel bit will not be released at this time.

void ListDestory(ListNode* phead)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = cur->next;
	}
	cur = NULL;
}

Guess you like

Origin blog.csdn.net/m0_57304511/article/details/123743356