数据结构之双向链表

讲过无头链表之后,双向链表就更好理解了
它的大致结构是这样子的:数据结构之双向链表
那么就是设计一个结构体来表示节点,很多人都用front,next来表示,但是我觉得左右更适合这样的图来理解,重要的不是变量名而是实现功能,数据结构就是为了存取数据存在的,所以这个我觉得只要自己能理解,就行:

struct node {
	int data;
	struct node* left;
	struct node* right;
};

我还用给我上一个数据结构的博客————数据结构之无头链表
所用的结构体封装来表示,这样的结构利于我们理解

struct list {
	struct node* headnode;
	struct node* tailnode;
	int size;
};

接下来是准备工作:创造节点的函数和两个“万金油”的函数是否为空函数和查询大小的函数

int listsize(struct list* plist) {
	return plist->size;
}
bool isempty(struct list* plist) {
	return (plist->size == 0);
}
struct node* createnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->left = NULL;
	newnode->right = NULL;
	newnode->data = data;
	return newnode;
}

创造节点就是初始化好就行了,没啥可解释的
接下来是构造列表函数:

struct list* createlist() {
	struct list* newlist = (struct list*)malloc(sizeof(struct list));
	newlist->headnode =newlist->tailnode = NULL;
	newlist->size = 0;
	return newlist;
}

构造一个空链表,头尾都为空

接下来是在头部添加元素
首先我们看原理图:数据结构之双向链表
需要注意的情况是,空链表的情况,插入的时候新节点不仅是头节点还是尾结点
其他情况按照这个图来:

void insertbyhead(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist))
		plist->tailnode = newnode;
	else {
		plist->headnode->left = newnode;
		newnode->right = plist->headnode;
	}
	plist->headnode = newnode;
	plist->size++;
}

尾结点的正好反过来,非常对称的一个关系,所以很轻松就实现了

void insertbytail(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist))
		plist->headnode = newnode;
	else {
		plist->tailnode->right = newnode;
		newnode->left = plist->tailnode;
	}
	plist->tailnode = newnode;
	plist->tailnode->right = NULL;
	plist->size++;
}

这里有必要说一下尾结点下一个节点初始化问题,这里必须要声明成NULL,这样print的时候不会出错,如果不初始化好,就会出现读取访问权限冲突0xCDCDCDCD的问题,其原因就是尾结点的初始化问题
接下来是在想要的的节点上插入节点:
数据结构之双向链表

void insertbyself(struct list* plist, int data, int posdata) {
	if (isempty(plist)) printf("空链表,找不到指定位置\n");
	else if (plist->size == 1 && plist->headnode->data == posdata|| plist->headnode->data == posdata) {
		insertbyhead(plist, data);
	}
	else {
		struct node* newnode = createnode(data);
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != NULL && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == NULL)printf("找不到元素\n");
		else {
			posfro->right = newnode;
			newnode->left = posfro;
			newnode->right = pos;
			pos->left = newnode;
		}
	}
}

这里要注意只有一个节点或者头节点的情况,只有一个的时候和头节点是所要插入的位置的时候,pos是找不到位置的。所以单独拿出来,并且他们的插入只需要调用在头节点插入的函数就行
其实跟无头链表非常一样多了一个指针罢了
接下来是删除的功能,其实现跟无头链表十分一样

void deletebyhead(struct list* plist) {
	if (isempty(plist)) printf("空链表无法删除");
	else {
		struct node* deletenode = plist->headnode;
		if (plist->size == 1) {
			plist->headnode = NULL;
			plist->tailnode = NULL;
		}
		else {
			plist->headnode = plist->headnode->right;
			plist->headnode->left = NULL;
		}
		free(deletenode);
	}
}

尾结点删除

void deletebytail(struct list* plist) {
	if (isempty(plist)) printf("空链表无法删除");
	else {
		struct node* deletenode = plist->tailnode;
		if (plist->size == 1) {
			plist->headnode = NULL;
			plist->tailnode = NULL;
		}
		else {
			plist->tailnode = plist->tailnode->left;
			plist->tailnode->right = NULL;
		}
		free(deletenode);
	}
}

画个图十分清晰
还有查找节点删除

void deletebyself(struct list* plist, int posdata) {
	if (isempty(plist)) printf("空链表,无法删除\n");
	else if (plist->size == 1 && plist->headnode->data == posdata || plist->headnode->data == posdata) {
		deletebyhead(plist);
	}
	else {
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != NULL && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == NULL)printf("找不到元素\n");
		else {
			struct node* deletenode = pos;
			posfro->right = pos->right;
			pos->right->left = posfro;
			free(deletenode);
		}
	}
}

跟上面的添加的情况一样的,也需要考虑头节点问题
删除元素的统一特点也是个无头链表一模一样的,需要一个临时的储存一下要删除的节点
以下是整体程序

#include<stdio.h>
#include<stdlib.h>
struct node {
	int data;
	struct node* left;
	struct node* right;
};
struct list {
	struct node* headnode;
	struct node* tailnode;
	int size;
};
int listsize(struct list* plist) {
	return plist->size;
}
bool isempty(struct list* plist) {
	return (plist->size == 0);
}
struct node* createnode(int data) {
	struct node* newnode = (struct node*)malloc(sizeof(struct node));
	newnode->left = NULL;
	newnode->right = NULL;
	newnode->data = data;
	return newnode;
}
struct list* createlist() {
	struct list* newlist = (struct list*)malloc(sizeof(struct list));
	newlist->headnode =newlist->tailnode = NULL;
	newlist->size = 0;
	return newlist;
}
void insertbyhead(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist))
		plist->tailnode = newnode;
	else {
		plist->headnode->left = newnode;
		newnode->right = plist->headnode;
	}
	plist->headnode = newnode;
	plist->size++;
}
void insertbytail(struct list* plist, int data) {
	struct node* newnode = createnode(data);
	if (isempty(plist))
		plist->headnode = newnode;
	else {
		plist->tailnode->right = newnode;
		newnode->left = plist->tailnode;
	}
	plist->tailnode = newnode;
	plist->tailnode->right = NULL;
	plist->size++;
}
void insertbyself(struct list* plist, int data, int posdata) {
	if (isempty(plist)) printf("空链表,找不到指定位置\n");
	else if (plist->size == 1 && plist->headnode->data == posdata|| plist->headnode->data == posdata) {
		insertbyhead(plist, data);
	}
	else {
		struct node* newnode = createnode(data);
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != NULL && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == NULL)printf("找不到元素\n");
		else {
			posfro->right = newnode;
			newnode->left = posfro;
			newnode->right = pos;
			pos->left = newnode;
		}
	}
}
void deletebyhead(struct list* plist) {
	if (isempty(plist)) printf("空链表无法删除");
	else {
		struct node* deletenode = plist->headnode;
		if (plist->size == 1) {
			plist->headnode = NULL;
			plist->tailnode = NULL;
		}
		else {
			plist->headnode = plist->headnode->right;
			plist->headnode->left = NULL;
		}
		free(deletenode);
	}
}
void deletebytail(struct list* plist) {
	if (isempty(plist)) printf("空链表无法删除");
	else {
		struct node* deletenode = plist->tailnode;
		if (plist->size == 1) {
			plist->headnode = NULL;
			plist->tailnode = NULL;
		}
		else {
			plist->tailnode = plist->tailnode->left;
			plist->tailnode->right = NULL;
		}
		free(deletenode);
	}
}
void deletebyself(struct list* plist, int posdata) {
	if (isempty(plist)) printf("空链表,无法删除\n");
	else if (plist->size == 1 && plist->headnode->data == posdata || plist->headnode->data == posdata) {
		deletebyhead(plist);
	}
	else {
		struct node* posfro = plist->headnode;
		struct node* pos = plist->headnode->right;
		while (pos != NULL && pos->data != posdata) {
			posfro = pos;
			pos = pos->right;
		}
		if (pos == NULL)printf("找不到元素\n");
		else {
			struct node* deletenode = pos;
			posfro->right = pos->right;
			pos->right->left = posfro;
			free(deletenode);
		}
	}
}
void printtoright(struct list* plist) {
	if (isempty(plist)) printf("空链表");
	else {
		struct node* pmove = plist->headnode;
		while (pmove) {
			printf("%d\t", pmove->data);
			pmove = pmove->right;
		}
		printf("\n");
	}
}
void printtoleft(struct list* plist) {
	if (isempty(plist)) printf("空链表");
	else {
		struct node* pmove = plist->tailnode;
		while (pmove) {
			printf("%d\t", pmove->data);
			pmove = pmove->left;
		}
		printf("\n");
	}
}

写完了,希望双向链表对你有帮助

上一篇:【数据结构学习】双向循环链表的插入、删除、查找、遍历、释放操作的C语言实现


下一篇:JS 数据结构和算法(五)双向链表