Data structure -- implementation of two-way linked list (review)

Posted by mellis95 on Fri, 28 Jan 2022 13:55:35 +0100

Compared with the previous sequential list and single linked list, the implementation of two-way linked list is more complex, but the actual operation link is simpler. For example, highways are more difficult to build than ordinary asphalt roads, but cars can run faster on highways.

It should be noted that the condition that the two-way lead linked list is empty is head - > next = next. No data is stored at the head node, which acts as a sentinel node. When there is only one sentinel node in the two-way linked list, it indicates that the two-way linked list is empty.

Definition of structure: a two-way linked list has two pointers and a value. These three parts can be considered when defining the structure.

typedef int LTDateType;
typedef struct ListNode
{
	LTDatetype data;
	struct ListNode* next;
	struct ListNode* prev;
}LTNode;

Initialization of sentinel position head node: it is necessary to initialize a head node for subsequent construction of linked list. Like the initialization of all nodes, you need to apply for a piece of structure type space from memory first. Then set the front and rear pointers to null. (this point is a sentinel position head node, so it does not need to be assigned)

LTNode* ListInit()
{
	LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
	phead->next = NULL;
	phead->prev = NULL;
	return phead;//Initializing a header node is naturally used. You need to return the address of this node for subsequent use
}

Node initialization: it is similar to the initialization of sentinel bit head node, except that an additional value needs to be assigned to the node.

LTNode* BuyListNode(LTDateType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	newnode->prev = NULL;
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}

Print bidirectional linked list:

void ListPrint(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;//Note that phead is the sentinel node. If you want to print from the first node, you need to find the next node of the sentinel node
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

Inserting a node at the end: it also involves the addition of nodes. First, you need to apply for a space, and the last four sentences can be drawn.

void ListPushBack(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

Delete a node at the end:

void ListPopBack(LTNode* phead)
{
	assert(phead);//If you want to delete the tail, you must first have something to delete. Therefore, the first two statements are to judge whether there is more than or equal to one node in the two-way linked list. It should be noted that the logical relationship between the two statements cannot be reversed.
	assert(phead->next != phead);
	LTNode* tail = phead->prev;
	phead->prev = tail->prev;
	tail->prev->next = phead;
	free(tail);//All pointers in this function have their own place. There is no need to set them to null, just free up space
}

Head inserting a node: it should be noted that the head inserting node should also be inserted between the sentinel node and the original head node.

void ListPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* newnode = BuyListNode(x);
	phead->next->prev = newnode;
	newnode->prev = phead;
	newnode->next = phead->next;
	phead->next = newnode;
}

Delete a node from the header:

void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next);//Like tail deletion, you need to ensure that there is at least one node in the two-way linked list
	LTNode* next = phead->next;
	LTNode* nextnext = next->next;
	nextnext->prev = phead;
	phead->next = nextnext;
	free(next);
}

Find a node with a value of x:

LTNode* ListFind(LTNode* phead, LTDateType x)
{
	assert(phead);
	assert(phead->next);
	LTNode* cur = phead->next;
	while (cur!=phead)//When cur=phead, it means that the two-way linked list has been traversed
	{
		if (cur->data = x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

Insert a node with a value of x at a specific location:

void ListInsert(LTNode* pos, LTDateType x)
{
	assert(pos);//There is no need to assert the header node this time, because it doesn't matter if the header node is empty during insertion
	LTNode* newnode = BuyListNode(x);
	LTNode* posPrev = pos->prev;//Unlike the single linked list, if you want to find a node, you can only find it from front to back (in one direction). If the double linked list finds the previous node of a node, you can directly find the prev of the node
	newnode->next = pos;
	pos->prev = newnode;
	posPrev->next = newnode;
	newnode->prev = posPrev;
}

Topics: data structure linked list