linked list|data structure

linked list structure

concept

The linked list is a non-continuous and non-sequential storage structure in the physical storage structure. The logical order of the data elements is realized through the link order of the pointers in the linked list.

insert image description here
By understanding the concept, we have a rough model, that is, each space has its own independent data content, and the connection between them is through saving the addresses in the front, and each of the latter is analogized in turn. So the next of the last one doesn't point. In fact, it is empty,
insert image description here
each space has data and the next address. Structures can be used for ease of management. Inside the structure is to save the address and data.

typedef int SLTDateType;
typedef struct SListNode
{
    
    
	SLTDateType data;
	struct SListNode* next;
}SListNode;

Although the structure is simple and uncomplicated, the key to learning linked lists is the use of pointers and the relationship between iterations before and after.

linked list type

In the data structure, the linked list can have a good transition. He can realize addition, deletion and search by himself. It is also possible to implement the data structure hash bucket substructure, the adjacency list of the graph for the future. As an offshoot of these data structure leaders, the foundation. The types are also diverse. There are 8 kinds of structures alone. Each has its own advantages.
1. One-way or two-way
insert image description here
2. Whether to take the lead
insert image description here
3. Whether to circulate

insert image description here
Combination can get one-way non-circulation without leading , two-way circulating with leading ...etc.
Although there are many combinations, it is practical to decide that there are only the above two types. It can also be said that this is a relatively classic structure among these structures.

structure realization

1. Singly linked list

The implementation of singly linked list is the use of pointers and iteration. Once understood. You will find that the difficulty of the linked list is not as difficult as imagined. Add, delete, insert and modify in the code. You can pay attention to the change of the pointed content of the pointer and the pointer type during implementation. This will give us more peace of mind and less crash and scratching when we debug.
Look directly at the code:

创建节点
SListNode* BuySListNode(SLTDateType x)
{
    
    
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
    
    
		perror("malloc fail");
		exit(-1);
	}


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

	return newnode;
}
尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
    
    
	SListNode* newnode = BuySListNode(x);
	SListNode* tail = NULL;
	if ((*pplist) == NULL)
	{
    
    
		*pplist = newnode;
	}
	else
	{
    
    
		tail = *pplist;
		//找尾
		while (tail->next)
		{
    
    
			tail = tail->next;
		}
		tail->next = newnode;

	}
}
尾删
void SListPopBack(SListNode** pplist)
{
    
    
	assert(*pplist);
	//一个节点单独判断
	if ((*pplist)->next == NULL)
	{
    
    
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
    
    
		SListNode* tail = *pplist;
		SListNode* pre = NULL;
		while (tail->next)
		{
    
    
			pre = tail;
			tail = tail->next;
		}
		free(tail->next);
		pre->next = NULL;

	}
}
打印
void SListPrint(SListNode* plist)
{
    
    
	SListNode* cur = plist;
	while (cur != NULL)
	{
    
    
		printf("%d-> ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
    
    
	SListNode* newhead = BuySListNode(x);
	newhead->next = *pplist;
	*pplist = newhead;
}
头删
void SListPopFront(SListNode** pplist)

{
    
    
	assert(*pplist);

	SListNode* next = (*pplist)->next;
	free(*pplist);
	*pplist = next;
}

Summary:
In the singly linked list, what needs to be changed for the operation of the linked list needs to pass any pointer, and for the node, it is a structure pointer. A struct pointer does not change the struct content. So realize call by address. There is also a deletion that needs to determine whether the linked list is empty to avoid the occurrence of null pointers.

2, with a two-way circular linked list

Implementation is relatively simple. This mainly depends on its own structural advantages.

typedef int LTDataType;
typedef struct ListNode
{
    
    
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

Double pointer advantage.
insert image description here

ListNode* Init()
{
    
    
	ListNode* new = ListCreate(-1);

	new->_next = new;
	new->_prev = new;

	return new;
}

It is not difficult to see from his initialization. Realize the leading advantage of linked list. There is also the list end condition. When the next of the head node points to the head node, the linked list is empty. code show as below:

// 创建返回链表的头结点.
ListNode* ListCreate(LTDataType x)
{
    
    
	ListNode* newnode= (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
    
    
		perror("fail");
		exit(-1);
	}
	newnode->_data = x;
	newnode->_next = NULL;
	newnode->_prev = NULL;

	return newnode;
}

// 双向链表销毁
void ListDestory(ListNode* pHead)
{
    
    
	assert(pHead);
	assert(pHead->_next != pHead);
	

	ListNode* tail = pHead->_prev;

	ListNode* tailprev = tail->_prev;
	tailprev->_next = pHead;
	pHead->_prev = tailprev;
	free(tail);

}

// 双向链表打印
void ListPrint(ListNode* pHead)
{
    
    
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur!=pHead)
	{
    
    
		printf("%d ", cur->_data);
		cur = cur->_next;
	}
	printf("\n");
}

// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
    
    
	assert(pHead);

	ListNode* newnode = ListCreate(x);

	ListNode* first = pHead->_next;

	first->_prev = newnode;
	newnode->_next = first;

	newnode->_prev = pHead;
	pHead->_next = newnode;
	
}

// 双向链表头删
void ListPopFront(ListNode* pHead)
{
    
    
	assert(pHead);
	assert(pHead->_next != pHead);

	ListNode* first = pHead->_next;

	ListNode* sconed = first->_next;
	free(first);

	sconed->_prev = pHead;
	pHead->_next = sconed;
}

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
    
    
	assert(pHead);
	ListNode* node = ListCreate(x);
	ListNode* tail = pHead->_prev;

	tail->_next = node;
	node->_prev = tail;

	node->_next = pHead;
	pHead->_prev = node;


}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
    
    
	assert(pHead);
	assert(pHead->_next != pHead);

	ListNode* tail = pHead->_prev;
	ListNode* tailprev = tail->_prev;
	
	tailprev->_next = pHead;
	pHead->_prev= tailprev;
	free(tail);
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
    
    
	assert(pos);
	ListNode* node = ListCreate(x);

	ListNode* prev = pos->_prev;
	prev->_next = node;
	node->_prev = prev;

	node->_next = pos;
	pos->_prev = node;

}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
    
    
	assert(pos);
	
	ListNode* prev = pos->_prev;
	ListNode* next = pos->_next;
	prev->_next = next;
	next->_prev = prev;

	free(pos);
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
    
    
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur != pHead)
	{
    
    
		if (cur->_data != x)
		{
    
    
			cur = cur->_next;
		}
		return cur;
	}
}

Summary:
The code implementation is relatively easy, and it is more popular and easy to understand than the singly linked list to achieve the same function. And the structural design itself is relatively perfect.

Guess you like

Origin blog.csdn.net/github_73587650/article/details/129648333