一、链表介绍

注:节点和结点只是说法、习惯的不同,本质上没有区别。

       单、双链表基本运算实现的核心算法是插入和删除操作,插入(删除)操作有前插(删)和后插(删)的区别,也有按值插入(删除)和按位序插入(删除)的区别,难点在于如何去找到合适插入(删除)的合适位置。

      一般而言,前插操作需要找到待插入元素(按值)待插入位序(按位序)的前驱;后插操作需要找到待插入元素所在的位置待插入的位序

1.类别


带头节点

不带头节点

单链表

循环

带头结点的单循环链表

不带头结点的单循环链表

不循环

带头结点的单链表

不带头结点的单链表

双链表

循环

带头结点的双循环链表

不带头结点的双循环链表

不循环

带头结点的双链表

不带头结点的双链表

注:本文实现的是带头结点的双链表

2.带头结点的双链表图示

4.带头节点的双链表的实现(C语言)_删除操作


二、涉及的基本运算总览

  1. 前插操作:往双链表D中第i位(前)插入值为e的元素(按位序)
  2. 前插操作:往双链表D中值为x的元素前面插入值为e的元素(按值)
  3. 删除操作:删除双链表D中位序为i的元素(按位序)
  4. 删除操作:删除双链表中值为x的元素(按值)
  5. 后插操作:往双链表D的第i位后面插入一个值为e的元素(按位序)
  6. 后插操作:往双链表D的第i位后面插入一个值为e的元素(按值)


三、具体代码实现

需要的头文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#define Elemtype int
1.定义存储结构
//1.定义存储结构
typedef struct LNode{
	Elemtype data;              //数据域
	struct LNode *pre, *next;   //指针域
}DLnode, *Double_link;


2.基本运算的代码实现
//2.初始化双链表
bool Init_Double_link(Double_link* D){
	(*D) = (Double_link)malloc(sizeof(DLnode));
	(*D)->data = 0;
	(*D)->pre = NULL;
	(*D)->next = NULL;
	return true;
}

//3.求双链表D的长度(元素个数)
int Count_length(Double_link D){
	int length = 0;
	while (D->next != NULL){
		length++;
		D = D->next;
	}
	return length;
}

//4.(1)前插操作:往双链表D中第i位(前)插入值为e的元素(按位序)
bool Insert_Dlist_e(Double_link* D, const int i, Elemtype e){
	//检查D是否存在
	assert(D);

	//判断插入位置i的合法性
	if (i < 1 || i > (Count_length(*D) + 1)) return false;

	//新建节点并初始化
	Double_link S = (Double_link)malloc(sizeof(DLnode));
	S->data = e;
	S->next = NULL;
	S->pre = NULL;
	Double_link P = (*D);

	//单独处理双链表为空情况
	if (P->next == NULL){
		P->next = S;
		S->pre = P;
	}
	else{
		//找到第i-1位
		for (int j = 1; j < i; j++){
			P = P->next;
		}
		//此时P指向第i-1位
		//处理正常情况(包括在末尾插入元素的情况),至少存在一个节点的情况
		if (i != Count_length(*D) + 1){
			P->next->pre = S;
			S->next = P->next;
		}
		P->next = S;
		S->pre = P;
	}
	
	return true;
}

//4.(2)前插操作:往双链表D中值为x的元素前面插入值为e的元素(按值)
bool Insert_Dlist_x(Double_link* D, Elemtype x, Elemtype e){
	assert(*D);

	Double_link P = (*D);

	//创建新节点
	Double_link S = (Double_link)malloc(sizeof(DLnode));
	S->data = e;
	S->pre = NULL;
	S->next = NULL;

	//单独处理双链表为空情况
	if (P->next == NULL){
		P->next = S;
		S->pre = P;
	}
	else{
		//找到值为x的前驱
		while (P->next != NULL && P->next->data != x){
			P = P->next;
		}
		if (!(P->next)) return false;
		if (P->next){
			P->next->pre = S;
			S->next = P->next;
		}
		P->next = S;
		S->pre = P;
		}
	return true;
}

//5.打印输出双链表D中的全部元素
void Print_Double_link(Double_link D){
	Double_link P = D->next;
	while (P != NULL){
		printf("%d ", P->data);
		P = P->next;
	}
	printf("\n");
}

//6.(1)按位序删除:删除双链表D中位序为i的元素
bool Delete_i(Double_link* D, const int i){

	//判断i的合法性
	if (i<1 || i>Count_length(*D)) return false;
	
	int j = 0;
	Double_link P = (*D), T;
	//找到第i-1位
	for (j = 1; j < i; j++){
		P = P->next;
	}
	T = P->next; //指向第i位元素
	if (T->next != NULL){
		T->next->pre = P;
	}
	P->next = T->next;
	free(T);
	return true;
}

//6.(2)按值删除:删除双链表中值为x的元素
bool Delete_x(Double_link* D, Elemtype x){
	
	Double_link P = (*D),T;
	//找到值为x的前驱节点
	while (P->next != NULL && P->next->data != x){
		P = P->next;
	}

	//此时P指向 1:值为x的节点的前驱;2:最后一个元素(即、链表中不存在值为x的元素)
	if (!(P->next)) return false;
	T = P->next;//指向值为x的节点(元素)
	if (T->next){  // T->next != NULL
		T->next->pre = P;
	}//这个if条件是处理当最后一个元素值为x时的情形(T->next==NULL)
	P->next = T->next;
	free(T);
	return true;
}

//7.(1)后插操作:往双链表D的第i位后面插入一个值为e的元素(按位序)
bool Insert_nex_i(Double_link* D, const int i, Elemtype e){
	assert(*D);
	//判断i的合法位置
	int len = Count_length(*D);
	if (i<1 || i>len) return false;
	//链表为空则终止
	if (len == 0) return false;
	//创建新节点
	Double_link S = (Double_link)malloc(sizeof(DLnode));
	S->data = e;
	S->next = NULL;
	S->pre = NULL;
	Double_link P = (*D);
	//找到第i位
	for (int j = 0; j < i; j++){
		P = P->next;
	}
	S->next = P->next;
	if (P->next){
		P->next->pre = S;
	}
	P->next = S;
	S->pre = P;
	return true;
}

//7.(2)后插操作:往双链表D的第i位后面插入一个值为e的元素(按值)
bool Insert_nex_x(Double_link* D, Elemtype x, Elemtype e){
	assert(*D);

	//创建新节点
	Double_link S = (Double_link)malloc(sizeof(DLnode));
	S->data = e;
	S->next = NULL;
	S->pre = NULL;
	Double_link P = (*D)->next;

	if (!P) return false;
	//找到值为x的元素
	while (P != NULL && P->data != x){
		P = P->next;
	}
	S->next = P->next;
	if (P->next){
		P->next->pre = S;
	}
	P->next = S;
	S->pre = P;
	return true;
}
3.main函数
//带头节点的双链表的实现
int main(){
	//1.声明变量
	Double_link D;

	//2.初始化双链表
	Init_Double_link(&D);
	

	//3.求双链表长度
	printf("%d \n", Count_length(D));

	//4.(1)前插操作(按位序)
	Insert_Dlist_e(&D, 1, 4);//头插
	printf("%d \n", Count_length(D));
	Insert_Dlist_e(&D, 2, 14);//尾插
	printf("%d \n", Count_length(D));
	Insert_Dlist_e(&D, 3, 24);//尾插
	printf("%d \n", Count_length(D));
	Insert_Dlist_e(&D, 2, 34);
	printf("%d \n", Count_length(D));
	Insert_Dlist_e(&D, 3, 44);
	printf("%d \n", Count_length(D)); //5
	Print_Double_link(D);//4 34 44 14 24 

	//4.(2)前插操作(按值)
	if (Insert_Dlist_x(&D, 14, 55)){
		printf("%d \n", Count_length(D)); //6
	}
	

	//5.打印操作
	Print_Double_link(D);//4 34 44 55 14 24 
	
	//6.删除操作
	//(1)按位删除
	Delete_i(&D,3);
	printf("%d \n", Count_length(D)); //5
	Print_Double_link(D); //4 34 55 14 24 
	//(2)按值删除
	if (Delete_x(&D, 4)){
		printf("%d \n", Count_length(D)); //4
		Print_Double_link(D); //34 55 14 24 
	}

	//7.(1)后插操作(按位序)
	Insert_nex_i(&D, 3, 23);
	Print_Double_link(D); //34 55 14 23 24 


	//7.(2)后插操作(按值)
	Insert_nex_x(&D, 34,32);
	Print_Double_link(D); //34 32 55 14 23 24
	
	return 0;
}
4.运行结果
0
1
2
3
4
5
4 34 44 14 24
6
4 34 44 55 14 24
5
4 34 55 14 24
4
34 55 14 24
34 55 14 23 24
34 32 55 14 23 24
请按任意键继续. . .

作者:QuestoQ   

欢迎大家交流指正。