Detailed explanation of linked list (single linked list, circular linked list, two-way linked list, Linux kernel "shared" double linked list) C/C++

Keywords: C++ Linux Algorithm data structure linked list

The complete code of single linked list, circular linked list, two-way linked list and Linux kernel "shared" double linked list is attached at the end of the article

catalogue

1, Detailed explanation of linked list principle

2, Implementation of single linked list algorithm

2.1 concept of single linked list  

2.2 single linked list initialization

2.3 adding elements to the single linked list

2.3.1 forward interpolation

2.3.2 tail interpolation method

2.3.3 insertion at any position

2.4 single linked list traversal

2.5 obtaining elements from single linked list

2.6 single linked list lookup elements

2.7 deleting elements from single linked list

2.8 destruction of single linked list

3, Implementation of circular linked list algorithm

Joseph problem

4, Implementation of bidirectional linked list algorithm

4.1 initialization of bidirectional linked list

4.2 adding elements to the two-way linked list

4.2.1 forward interpolation

4.2.2 tail interpolation method

4.2.3 insertion at any position

4.3 two way linked list traversal

4.4 obtaining elements from bidirectional linked list

4.5 deleting elements from a two-way linked list

4.6 destruction of two-way linked list

5, Linux kernel "shared" bidirectional linked list

Single linked list complete code

Complete code of circular linked list

Two way linked list complete code

1, Detailed explanation of linked list principle

A linked list is a chain storage method of a linear list. Logically, the storage locations of adjacent data in the computer do not have to be adjacent
How to express logical adjacency? You can attach a pointer field to each element, pointing to the storage bit of the next element
Set. As shown in the figure:

As can be seen from the figure, each node contains two fields: data field and pointer field. The pointer field stores the address of the next node,
Therefore, the type pointed to by the pointer is also a node type.

  Core elements of linked list:

          I each node consists of data field and pointer field
         The II pointer field points to the memory address of the next node

Its structure definition
typedef struct LinkNode{
    ElemType data;
    struct LinkNode *next;
}LinkList, LinkNode;

2, Implementation of single linked list algorithm

2.1 concept of single linked list  

The nodes of the linked list all point to the next node in one direction, forming a one-way access data chain  

2.2 single linked list initialization

typedef struct _LinkNode {
    int data; //Data field of node
    struct _LinkNode *next; //Pointer field of node
}LinkNode, LinkList; //Linked list node, linked list

bool InitList(LinkList* &L){//Construct an empty single linked list L
    L=new LinkNode; //Generate a new node as the head node, and point to the head node with the head pointer L
    if(!L)return false; //Failed to generate node
    L->next=NULL; //The pointer field of the header node is set to null
    return true;
}

2.3 adding elements to the single linked list

2.3.1 forward interpolation

//Forward interpolation
bool ListInsert_front(LinkList* &L, LinkNode * node){
    if(!L || !node ) return false;
    node->next = L->next;
    L->next = node;
    return true;
}

2.3.2 tail interpolation method

//Tail interpolation
bool ListInsert_back(LinkList* &L, LinkNode *node){
    LinkNode *last = NULL;
    if(!L || !node ) return false;
    //Last node found
    last = L;
    while(last->next) last=last->next;
    //The new node is linked to the tail
    node->next = NULL;
    last->next = node;
    return true;
}

2.3.3 insertion at any position

//Arbitrary position interpolation
bool LinkInsert(LinkList* &L, int i, int &e){//Insertion of single linked list
//Insert a new node with a value of e at the ith position in the single linked list L of the leading node
    int j;
    LinkList *p, *s;
    p=L;
    j=0;
    while (p&&j<i-1){ //Find the i-1 node, and p points to it
        p=p->next;
        j++;
    }
    if (!p || j>i-1){//i > n+1 or i < 1
        return false;
    }
    s=new LinkNode; //Generate new node
    s->data=e; //Set the data field of the new node to e
    s->next=p->next; //Point the pointer field of the new node to the node ai
    p->next=s; //Point the pointer field of node p to node s
    return true;
}

2.4 single linked list traversal

void LinkPrint(LinkList* &L) {//Output of single linked list
    LinkNode* p;
    p=L->next;
    while (p){
    cout <<p->data <<"\t";
    p=p->next;
    }
    cout<<endl;
}

2.5 obtaining elements from single linked list

bool Link_GetElem(LinkList* &L, int i, int &e){//Value of single linked list
    //Find the ith element in the single linked list L of the leading node
    //Record the value of the ith data element in L with e
    int j;
    LinkList* p;
    p=L->next;//p points to the first node,
    j=1; //j is the counter
    while (j<i && p){ //Scan the chain domain backward until p points to the ith element or p is empty
    p=p->next; //p points to the next node
    j++; //Counter j is incremented by 1 accordingly
    }
    if (!p || j>i){
    return false; //Illegal i value i > n or i < = 0
    }
    e=p->data; //Take the data field of the ith node
    return true;
}

2.6 single linked list lookup elements

bool Link_FindElem(LinkList *L, int e){ //Find by value
    //Find the element with value e in the single linked list L of the leading node
    LinkList *p;
    p=L->next;
    while (p && p->data!=e){//Scan the chain domain backward until p is empty or the data domain of the node referred to by p is equal to e
        p=p->next; //p points to the next node
    }
    if(!p)return false; //Lookup failed. p is NULL
    return true;
}

2.7 deleting elements from single linked list

bool LinkDelete(LinkList* &L, int i){ //Deletion of single linked list
    //In the single linked list L of the leading node, delete the ith position
    LinkList *p, *q;
    int j;
    p=L;
    j=0;
    while((p->next)&&(j<i-1)){ //Find the i-1 node, and p points to it
        p=p->next;
        j++;
    }
    if (!(p->next)||(j>i-1))//When I > n or I < 1, the deletion position is unreasonable
        return false;
    q=p->next; //Temporarily save the address of the deleted node for free space
    p->next=q->next; //Change the pointer field of the precursor node of the deleted node
    delete q; //Free up space for deleted nodes
    return true;
}

2.8 destruction of single linked list

void LinkDestroy(LinkList* &L) {//Destruction of single linked list
    //Define the temporary node p to point to the header node
    LinkList *p = L;
    cout<<"Destroy linked list!"<<endl;
    while(p){
        L=L->next; //L points to the next node
        cout<<"Delete element: "<<p->data<<endl;
        delete p; //Delete current node
        p=L; //p move to next node
    }
}

  Complete code implementation:

3, Implementation of circular linked list algorithm

Joseph problem

  There are 10 children in numbered order 1, 2,..., 10 circle clockwise. Starting from No. 1, clockwise 1, 2,..., 9. Those who report 9 are listed (obviously, the first circle is numbered 9).
What is the number of the last person out of the circle? What is the number of the fifth person out of the circle?

The complete code of circular linked list is attached at the end of the article~

4, Implementation of bidirectional linked list algorithm

In addition to storing its own data, each node in the single linked list also stores the address of the next node, so you can easily access the next node and subsequent nodes, but you can't go back if you want to access the previous node. For example, when deleting node p, first find its previous node q, and then delete node p. the one-way linked list can only go back, not forward. What if you need to move forward?
You can attach two pointer fields to each element based on the single linked list, one to store the address of the previous element and the other to store the address of the next element. This kind of linked list is called bidirectional linked list.

Its structure definition:
typedef struct _LinkNode {
    int data; //Data field of node
    struct _LinkNode *next; //Pointer field of the next node
    struct _LinkNode *prev; //Pointer field of the previous node
}LinkNode, LinkList; //LinkList is the pointer type to the structure LNode

4.1 initialization of bidirectional linked list

typedef struct _DoubleLinkNode {
	int data; //Data field of node
	struct _DoubleLinkNode* next; //Pointer field of the next node
	struct _DoubleLinkNode* prev; //Pointer field of the previous node
}DbLinkNode, DbLinkList; //LinkList is the pointer type to the structure LNode

bool DbInit_List(DbLinkList*& L){//Construct an empty two-way linked list L
	L = new DbLinkNode; //Generate a new node as the head node, and point to the head node with the head pointer L
	if (!L)return false; //Failed to generate node
	L->next = NULL; //The next pointer field of the header node is null
	L->prev = NULL; //The pointer field of the header node is set to null
	L->data = -1;
	return true;
}

4.2 adding elements to the two-way linked list

4.2.1 forward interpolation

//Forward interpolation
bool DbListInsert_front(DbLinkList*& L, DbLinkNode* node) {
	if (!L || !node) return false;
	//1. Only header nodes
	if (L->next == NULL) {
		node->next = NULL;
		node->prev = L; //The new node prev pointer points to the header node
		L->next = node; //The next pointer of the header node points to the new node
	}
	else {
		L->next->prev = node; //The prev of the second node points to the new node
		node->next = L->next; //The new node next pointer points to the second node
		node->prev = L; //The new node prev pointer points to the header node
		L->next = node; //The next pointer of the header node points to the new node to complete the insertion
	}
	return true;
}

4.2.2 tail interpolation method

//Tail interpolation
bool DbListInsert_back(DbLinkList*& L, DbLinkNode* node) {
	DbLinkNode* last = NULL;
	if (!L || !node) return false;
	last = L;
	while (last->next) last = last->next;
	node->next = NULL;
	node->prev = last;
	return true;
}

4.2.3 insertion at any position

//Insert at specified location
bool DbLink_Insert(DbLinkList*& L, int i, int& e) {
	if (!L || !L->next) return false;
	if (i < 1) return false;
	int j = 0;
	DbLinkList* p, * s;
	p = L;
	while (p && j < i) {//Find the node with position i, and p points to the node
		p = p->next;
		j++;
	}
	if (!p || j != i) {
		cout << "Node does not exist:" << i << endl;
		return false;
	}
	cout << "p: " << p << endl;
	s = new DbLinkNode;//Generate new node
	s->data = e;
	s->next = p;
	s->prev = p->prev;
	p->prev->next = s;
	p->prev = s;
	return true;
}

4.3 two way linked list traversal

//Traversal output of bidirectional linked list
void DbLink_Print(DbLinkList*& L) {
	DbLinkNode* p = NULL;
	if (!L) {
		cout << "The linked list is empty." << endl;
		return;
	}
	p = L;
	while (p->next) {
		cout << p->next->data << "\t";
		p = p->next;
	}
	//Reverse printing
	cout << endl << "Reverse printing" << endl;
	while (p) {
		cout << p->data << "\t";
		p = p->prev;
	}
	cout << endl;
}

4.4 obtaining elements from bidirectional linked list

bool DbLink_GetElem(DbLinkList*& L, int i, int& e){//Value of bidirectional linked list
	//Find the ith element in the two-way linked list L of the leading node
	//Record the value of the ith data element in L with e
	int index;
	DbLinkList* p;
	if (!L || !L->next) return false;
	p = L->next;
	index = 1;
	while (p && index < i) {//Scan the list backward until p points to the ith element or p is empty
		p = p->next; //p points to the next node
		index++; //The counter index is incremented by 1 accordingly
	}
	if (!p || index > i) {
		return false; //Illegal value of i, i > n or i < = 0
	}
	e = p->data;
	return true;
}

4.5 deleting elements from a two-way linked list

//Delete anywhere
bool DbLink_Delete(DbLinkList*& L, int i) //Deletion of bidirectional linked list
{
	DbLinkList* p;
	int index = 0;
	if (!L || !L->next) {
		cout << "The two-way linked list is empty!" << endl;
		return false;
	}
	if (i < 1) return false; //You cannot delete a header node
	p = L;
	while (p && index < i) {
		p = p->next;
		index++;
	}
	if (!p) { //Failure is returned when the node does not exist
		return false;
	}
	p->prev->next = p->next; //Change the next pointer field of the predecessor node of the deleted node
	if (p->next) {
		p->next->prev = p->prev; //Change the prev pointer field of the successor node after deleting the node
	}
	delete p; //Free up space for deleted nodes
	return true;
}

4.6 destruction of two-way linked list

void DbLink_Destroy(DbLinkList*& L){ //Destruction of bidirectional linked list
	//Define the temporary node p to point to the header node
	DbLinkList* p = L;
	cout << "Destroy linked list!" << endl;
	while (p) {
		L = L->next;//L points to the next node
		cout << "Delete element: " << p->data << endl;
		delete p; //Delete current node
		p = L; //p move to next node
	}
}

5, Linux kernel "shared" bidirectional linked list

In the linux kernel, a large number of data structures need to use two-way linked lists, such as processes, files, modules, pages and so on. If we adopt the traditional implementation of two-way linked list, we need to maintain their own linked list for these data structures, and design operation functions such as insert and delete for each linked list. Because the next and prev pointers used to maintain the linked list point to the corresponding types of objects, the linked list operation function of one data structure cannot be used to operate the linked list of other data structures.
For example, we need to define the linked list structure of stars and web server timeout respectively:  

one. web Linked list structure of server timeout
typedef struct {
    int fd ;
    time_t timeout; // Use the timestamp of the timeout time
}ConnTimeout;

struct Link_Node{
    ConnTimeout conn;
    struct Link_Node *next;
}

two.Linked list structure of bright starry sky
typedef struct {
    int x; //x coordinate of the star
    int y; //y coordinates of stars
    enum STATUS stat; //state
    unsigned radius; //Radius of stars
    int step; //Interval per jump
    int color; //The color of stars
}STAR;

struct Link_Node{
    STAR star;
struct Link_Node *next;
}

Is there a way for multiple linked lists to share the same set of linked lists? See the figure below:

 

typedef struct _DoubleLinkNode {
    struct _DoubleLinkNode *next; //Pointer field of the next node
    struct _DoubleLinkNode *prev; //Pointer field of the previous node
}DbLinkNode;

typedef struct {
    int fd ;
    time_t timeout; // Use the timestamp of the timeout time
    DbLinkNode node; // Bidirectional linked list node "Pendant"
}ConnTimeout;

typedef struct {
    int x; //x coordinate of the star
    int y; //y coordinates of stars
    enum STATUS stat; //state
    unsigned radius; //Radius of stars
    int step; //Interval per jump
    int color; //The color of stars
    DbLinkNode node; // Bidirectional linked list node "Pendant"
}STAR;

Key points:
         offsetof can be used to deduce the position of structure variable according to the address of linked list node in structure
         For example:

typedef struct {
    int fd ;
    time_t timeout; // Use the timestamp of the timeout time
    DbLinkNode node; // Bidirectional linked list node "Pendant"
}ConnTimeout;

//Access the data hosted by the node through the node
ConnTimeout *ct = new ConnTimeout;
DbLinkNode *p = &(ct->node);
cout<<"Please enter the value corresponding to the timeout node fd: ";
cin>>ct->fd;
cout<<"\n Access the data carried on the node through the node in the linked list:"<<endl;
int offset = offsetof(ConnTimeout, node);
ConnTimeout *tmp = (ConnTimeout *)((size_t)p-offset);
printf("offset: %d\n", offset);
printf("Through linked list node node Data accessed:%d\n", tmp->fd);

Source code implementation

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
typedef struct _DoubleLinkNode {
	//int data; // Data field of node
	struct _DoubleLinkNode* next; //Pointer field of the next node
	struct _DoubleLinkNode* prev; //Pointer field of the previous node
}DbLinkNode, DbLinkList; //LinkList is the pointer type to the structure LNode
typedef struct {
	int fd;
	time_t timeout; // Use the timestamp of the timeout time
	DbLinkNode node; // Bidirectional linked list node "Pendant"
}ConnTimeout;
typedef struct {
	int x; //x coordinate of the star
	int y; //y coordinates of stars
	enum STATUS stat; //state
	unsigned radius; //Radius of stars
	int step; //Interval per jump
	int color; //The color of stars
	DbLinkNode node; // Bidirectional linked list node "Pendant"
}STAR;
bool DbList_Init(DbLinkList& L){//Construct an empty two-way linked list L
	L.next = NULL; //The next pointer field of the header node is null
	L.prev = NULL; //The prev pointer field of the header node is null
	return true;
}

//Tail interpolation
bool DbListInsert_back(DbLinkList & L, DbLinkNode & node) {
	DbLinkNode* last = NULL;
	last = &L;
	while (last->next) last = last->next;
	node.next = NULL;
	last->next = &node;
	node.prev = last;
	return true;
}
int main(void) {
	ConnTimeout* cl = NULL, * s = NULL;
	STAR* sl = NULL;
	int n = 0;
	//1. Initialize an empty two-way linked list
	cl = new ConnTimeout;
	cl->fd = -1;
	sl = new STAR;
	sl->x = -1;
	DbList_Init(cl->node);
	DbList_Init(sl->node);
	//2. Insert data using tail interpolation
	cout << "Creating bidirectional linked list by tail interpolation" << endl;
	std::cout << "Please enter the number of elements n: ";
	cin >> n;
	cout << "\n Please enter in sequence n File handle for elements:" << endl;
	while (n > 0) {
		s = new ConnTimeout; //Generate new node s
		cin >> s->fd;
		printf("s Address of:%p node: %p\n", s, &(s->node));
		DbListInsert_back(cl->node, s->node);
		n--;
	}
	//3. Access data according to linked list nodes
	DbLinkNode* p = NULL;
		p = &(cl->node);
	cout << "Traverse the nodes in the connection timeout linked list:" << endl;
	while (p) {
		int offset = offsetof(ConnTimeout, node);
		ConnTimeout* ct = (ConnTimeout*)((size_t)p - offset);
		cout << ct->fd << endl;
		p = p->next;
	}
	//4. Destroy the two-way linked list
	p = &(cl->node);
	cout << "Destroy nodes in the connection timeout linked list:" << endl;
	while (p) {
		int offset = offsetof(ConnTimeout, node);
		ConnTimeout* ct = (ConnTimeout*)((size_t)p - offset);
		printf("offset: %u ct: %p p:%p\n", offset, ct, p);
		cout << ct->fd << endl;
		p = p->next;
		delete ct;
	}
	system("pause");
	return 0;
}

Single linked list complete code

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
typedef struct _LinkNode {
	int data; //Data field of node
	struct _LinkNode* next; //Pointer field of node
}LinkNode, LinkList; //LinkList is the pointer type to the structure LNode

bool InitList(LinkList*& L) {
	L = new LinkNode;
	if (!L) return false;//Failed to generate node
	L->next = NULL;
	L->data = -1;

	return true;
}
//Forward interpolation
bool ListInsert_front(LinkList*& L, LinkNode* node) {
	if (!L || !node) return false;
	node->next = L->next;
	L->next = node;
	return true;
}
//Tail interpolation
bool ListInsert_back(LinkList*& L, LinkNode* node) {
	LinkNode* last = NULL;
	if (!L || !node) return false;
	last = L;
	while (last->next) last = last->next;
	node->next = NULL;
	last->next = node;
	return true;
}
//Insert at specified location
bool LinkInsert(LinkList*& L, int i, int& e) {
	if (!L) return false;
	int j = 0;
	LinkList* p, * s;
	p = L;
	while (p && j < i - 1) {//Find the node with position i-1, and p points to the node
		p = p->next;
		j++;
	}
	if (!p || j > i - 1) {
		return false;
	}
	s = new LinkNode;//Generate new node

	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}
void LinkPrint(LinkList*& L) {
	LinkNode* p = NULL;
	if (!L) {
		cout << "The linked list is empty." << endl;
		return;
	}
	p = L->next;
	while (p) {
		cout << p->data << "\t";
		p = p->next;
	}
	cout << endl;
}
bool Link_GetElem(LinkList*& L, int i, int& e)//Value of single linked list
{
	//Find the ith element in the single linked list L of the leading node
	//Record the value of the ith data element in L with e
	int index;
	LinkList* p;
	if (!L || !L->next) return false;
	p = L->next;
	index = 1;
	while (p && index < i) {//Scan the list backward until p points to the ith element or p is empty
		p = p->next; //p points to the next node
		index++; //The counter index is incremented by 1 accordingly
	}
	if (!p || index > i) {
		return false; //Illegal value of i, i > n or i < = 0
	}

		e = p->data;
	return true;
}
bool Link_FindElem(LinkList* L, int e, int& index) //Find by value
{
	//Find the element with value e in the single linked list L of the leading node
	LinkList* p;
	p = L->next;
	index = 1;
	if (!L || !L->next) {
		index = 0;
		return false;
	}
	while (p && p->data != e) {
		p = p->next;
		index++;
	}
	if (!p) {
		index = 0;
		return false;//No such value found
	}
	return true;
}
bool LinkDelete(LinkList*& L, int i) //Deletion of single linked list
{
	LinkList* p, * q;
	int index = 0;
	p = L;
	if (!L || !L->next) {
		return false;
	}
	while ((p->next) && (index < i - 1)) {
		p = p->next;
		index++;
	}

	if (!p->next || (index > i - 1)) { //When I > n or I < 1, the deletion position is unreasonable
		return false;
	}
	q = p->next; //Temporarily save the address of the deleted node for free space
	p->next = q->next;//Change the pointer field of the precursor node of the deleted node
	delete q; //Free up space for deleted nodes
	return true;
}
void LinkDestroy(LinkList*& L) //Destruction of single linked list
{
	//Define the temporary node p to point to the header node
	LinkList* p = L;
	cout << "Destroy linked list!" << endl;
	while (p) {
		L = L->next;//L points to the next node
		cout << "Delete element: " << p->data << endl;
		delete p; //Delete current node
		p = L; //p move to next node
	}
}
int main(void) {
	LinkList* L = NULL;
	LinkNode* s = NULL;
	//1. Initialize an empty linked list
	InitList(L);
	//2. Insert data using forward interpolation
	/*int n;
	cout<<"Create single linked list "< < endl" by pre interpolation;
	std::cout<<"Please enter the number of elements n: ";
	cin>>n;
	cout<<"\n Please enter n elements in sequence: "< < endl;
	while(n>0){
	s = new LinkNode; //Generate new node s
	cin>>s->data;
	ListInsert_front(L, s);
	n--;

	}
	*/
	//3. Insert data using tail interpolation
	/*int n;
	cout<<"Create single linked list "< < endl" by tail interpolation;
	std::cout<<"Please enter the number of elements n: ";
	cin>>n;
	cout<<"\n Please enter n elements in sequence: "< < endl;
	while(n>0){
	s = new LinkNode; //Generate new node s
	cin>>s->data;
	ListInsert_back(L, s);
	n--;
	}
	//4. Output of single linked list
	LinkPrint(L);
	*/
	//5. Insert elements anywhere
	for (int j = 0; j < 3; j++) {
		int i, x;
		cout << "Please enter the insertion position and elements (separated by spaces):";
		cin >> i;
		cin >> x;
		if (LinkInsert(L, i, x)) {
			cout << "Insert successful.\n\n";
		}
		else {
			cout << "Insert failed!\n\n";
		}
		LinkPrint(L);
	}
	//6. The single linked list obtains elements according to location
	int element = 0;
	if (Link_GetElem(L, 2, element)) {
		cout << "Getting the second element succeeded, Value:" << element << endl;
	}
	else {
		cout << "Failed to get the second element!" << endl;
	}
	//7. The single linked list queries the location of the element according to the value
	int index = 0;

	if (Link_FindElem(L, 10, index)) {
		cout << "Find element 10 exists,location: " << index << endl;
	}
	else {
			cout << "Element 10 does not exist." << endl;
	}
	//8. Delete elements from single linked list
	if (LinkDelete(L, 2)) {
		cout << "The second element was deleted successfully!" << endl;
		LinkPrint(L);
	}
	else {
		cout << "Failed to delete the 2nd element!" << endl;
	}
	//9. Destroy the single linked list
	LinkDestroy(L);
	system("pause");
	return 0;
}

Complete code of circular linked list

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
typedef struct _LinkNode {
	int data; //Data field of node
	struct _LinkNode* next; //Pointer field of node
}LinkNode, LinkList; //LinkList is the pointer type to the structure LNode
void LinkPrint(LinkList* L);
bool InitList(LinkList*& L){//Construct an empty circular linked list L

	L = new LinkNode; //Generate a new node as the head node, and point to the head node with the head pointer L
	if (!L)return false; //Failed to generate node
	L->next = L; //The pointer field of the header node points to itself
	L->data = -1;
	return true;
}
//Tail interpolation
bool ListInsert_back(LinkList*& L, LinkNode* node) {
	LinkNode* last = NULL;
	if (!L || !node) return false;

	//Last node found
	last = L;
	while (last->next != L) last = last->next;
	//The new node is linked to the tail
	node->next = L;
	last->next = node;
	return true;
}
bool Joseph(LinkList*& L, int interval)
{
	//In the circular linked list L of the leading node, each interval circularly deletes the node
	LinkList* p, * q;
	int j = 0, i = 0;
	int times = 0, num = 0;
	p = L;
	if (!L || p->next == L) {
		cout << "The linked list is empty!" << endl;
		return false;
	}
	if (interval < 1) {
		cout << "The number elimination password cannot be less than 1!" << endl;
		return false;
	}
	do {
		i += interval;
		while ((p->next)){ //Find the ith node, and p points to the previous node of the node
		
			if (p->next != L) j++;
			if (j >= i) break;
			p = p->next;
		}
		times++;
		/*if (!(p->next)||(j>i))//When I > n or I < 1, the deletion position is unreasonable
		return false;*/
		q = p->next; //Temporarily save the address of the deleted node for free space
		num = q->data;

			if (times == 5) cout << "The number of the fifth out circle is:" << num << endl;
		printf("cur: %d last: %d next:%d\n", q->data, p->data,
			q->next->data);
		p->next = q->next; //Change the pointer field of the precursor node of the deleted node
		delete q; //Free up space for deleted nodes
		LinkPrint(L);
	} while (L->next != L);//The linked list is not empty. Continue counting
	cout << "The number of the last circle is:" << num << endl;
	return true;
}
void LinkPrint(LinkList* L) //Output of circular linked list
{
	LinkList* p;
	if (!L || L == L->next) {
		cout << "The linked list is empty!" << endl;
		return;
	}
	p = L->next;
	while (p != L){
		cout << p->data << "\t";
		p = p->next;
	}
	cout << endl;
}
int main() {
	int i, x;
	LinkList* L;
	LinkNode* s;
	//1. Initialize an empty circular linked list
	if (InitList(L)) {
		cout << "Initialize an empty circular linked list!\n";
	}
	//2. Create a circular linked list (tail insertion method)

	std::cout << "Creating circular linked list by tail interpolation, Insert 10 elements..." << endl;
	i = 0;
	while ((++i) <= 10){
		s = new LinkNode;//Generate new node
		s->data = i; //The input element value is assigned to the data field of the new node
		s->next = NULL;
		if (ListInsert_back(L, s)) {
			cout << "Insert successful!" << endl;
		}
		else {
			cout << "Insert failed!" << endl;
		}
	}
	cout << "Tail interpolation method to create circular linked list output results:\n";
	LinkPrint(L);
	//3. Answer Joseph's questions
	Joseph(L, 9);
	system("pause");
	return 0;
}

Two way linked list complete code

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
typedef struct _DoubleLinkNode {
	int data; //Data field of node
	struct _DoubleLinkNode* next; //Pointer field of the next node
	struct _DoubleLinkNode* prev; //Pointer field of the previous node
}DbLinkNode, DbLinkList; //LinkList is the pointer type to the structure LNode

bool DbList_Init(DbLinkList*& L){//Construct an empty two-way linked list L

	L = new DbLinkNode; //Generate a new node as the head node, and point to the head node with the head pointer L
	if (!L)return false; //Failed to generate node
	L->next = NULL; //The next pointer field of the header node is null
	L->prev = NULL; //The prev pointer field of the header node is null
	L->data = -1;
	return true;
}
//Forward interpolation
bool DbListInsert_front(DbLinkList*& L, DbLinkNode* node) {
	if (!L || !node) return false;
	//1. Only header nodes
	if (L->next == NULL) {
		node->next = NULL;
		node->prev = L; //The new node prev pointer points to the header node
		L->next = node; //The next pointer of the header node points to the new node
	}
	else {
		L->next->prev = node; //The prev of the second node points to the new node
		node->next = L->next; //The new node next pointer points to the second node
		node->prev = L; //The new node prev pointer points to the header node
		L->next = node; //The next pointer of the header node points to the new node to complete the insertion
	}
	return true;
}
//Tail interpolation
bool DbListInsert_back(DbLinkList*& L, DbLinkNode* node) {
	DbLinkNode* last = NULL;
	if (!L || !node) return false;
	last = L;
	while (last->next) last = last->next;
	node->next = NULL;
	last->next = node;
	node->prev = last;
	return true;
}
//Insert at specified location
bool DbLink_Insert(DbLinkList*& L, int i, int& e) {
	if (!L || !L->next) return false;
	if (i < 1) return false;
	int j = 0;
	DbLinkList * p, * s;
	p = L;
	while (p && j < i) {//Find the node with position i, and p points to the node
		p = p->next;
		j++;
	}
	if (!p || j != i) {
		cout << "Node does not exist:" << i << endl;
		return false;
	}
	cout << "p: " << p << endl;
	s = new DbLinkNode;//Generate new node
	s->data = e;
	s->next = p;
	s->prev = p->prev;
	p->prev->next = s;
	p->prev = s;
	return true;
}
void DbLink_Print(DbLinkList*& L) {
	DbLinkNode* p = NULL;
	if (!L) {
		cout << "The linked list is empty." << endl;
		return;
	}
	p = L;
	while (p->next) {
		cout << p->next->data << "\t";
		p = p->next;
	}
	//Reverse printing
	cout << endl << "Reverse printing" << endl;
	while (p) {
		cout << p->data << "\t";
		p = p->prev;
	}
	cout << endl;
}
bool DbLink_GetElem(DbLinkList*& L, int i, int& e){//Value of bidirectional linked list
	//Find the ith element in the two-way linked list L of the leading node
	//Record the value of the ith data element in L with e
	int index;
	DbLinkList* p;
	if (!L || !L->next) return false;
	p = L->next;
	index = 1;
	while (p && index < i) {//Scan the list backward until p points to the ith element or p is empty
		p = p->next; //p points to the next node
		index++; //The counter index is incremented by 1 accordingly
	}
	if (!p || index > i) {
		return false; //Illegal value of i, i > n or i < = 0
	}
	e = p->data;
	return true;
}
bool DbLink_Delete(DbLinkList*& L, int i){ //Deletion of bidirectional linked list
	DbLinkList* p;
	int index = 0;
	if (!L || !L->next) {
		cout << "The two-way linked list is empty!" << endl;
		return false;
	}
	if (i < 1) return false; //You cannot delete a header node
	p = L;
	while (p && index < i) {
		p = p->next;
		index++;
	}
	if (!p) { //Failure is returned when the node does not exist
		return false;
	}
	p->prev->next = p->next; //Change the next pointer field of the predecessor node of the deleted node
	p->next->prev = p->prev; //Change the prev pointer field of the successor node after deleting the node
	delete p; //Free up space for deleted nodes
	return true;
}
void DbLink_Destroy(DbLinkList*& L) {//Destruction of bidirectional linked list
	//Define the temporary node p to point to the header node
	DbLinkList* p = L;
	cout << "Destroy linked list!" << endl;
	while (p) {
		L = L->next;//L points to the next node
		cout << "Delete element: " << p->data << endl;
		delete p; //Delete current node
		p = L; //p move to next node
	}
}
int main(void) {
	DbLinkList* L = NULL;
	DbLinkNode* s = NULL;
	//1. Initialize an empty two-way linked list
	DbList_Init(L);
	//2. Insert data using forward interpolation
	int n;
	cout << "Creating bidirectional linked list by forward interpolation" << endl;
	std::cout << "Please enter the number of elements n: ";
	cin >> n;
	cout << "\n Please enter in sequence n Elements:" << endl;
	while (n > 0) {
		s = new DbLinkNode; //Generate new node s
		cin >> s->data;
		DbListInsert_front(L, s);
		n--;
	}
	//3. Insert data using tail interpolation
	cout << "Creating bidirectional linked list by tail interpolation" << endl;
	std::cout << "Please enter the number of elements n: ";
	cin >> n;
	cout << "\n Please enter in sequence n Elements:" << endl;
	while (n > 0) {
		s = new DbLinkNode; //Generate new node s
		cin >> s->data;
		DbListInsert_back(L, s);
		n--;
	}
	//4. Output of bidirectional linked list
	DbLink_Print(L);
	//5. Insert elements anywhere
	for (int j = 0; j < 3; j++) {
		int i, x;
		cout << "Please enter the insertion position and elements (separated by spaces):";
		cin >> i;
		cin >> x;
		if (DbLink_Insert(L, i, x)) {
			cout << "Insert successful.\n\n";
		}
		else {
			cout << "Insert failed!\n\n";
		}
		DbLink_Print(L);
	}
	//6. The two-way linked list obtains elements according to location
	int element = 0;
	if (DbLink_GetElem(L, 2, element)) {
		cout << "Getting the second element succeeded, Value:" << element << endl;
	}
	else {
		cout << "Failed to get the second element!" << endl;
	}
	//7. Delete elements from the two-way linked list
	if (DbLink_Delete(L, 2)) {
		cout << "The second element was deleted successfully!" << endl;
		DbLink_Print(L);
	}
	else {
		cout << "Failed to delete the 2nd element!" << endl;
	}
	if (DbLink_Delete(L, 1)) {
		cout << "The first element was deleted successfully!" << endl;
		DbLink_Print(L);
	}
	else {
		cout << "Failed to delete the first element!" << endl;
	}
	//8. Destroy the two-way linked list
	DbLink_Destroy(L);
	system("pause");
	return 0;
}

Posted by jbradley04 on Tue, 16 Nov 2021 20:49:42 -0800