讲过无头链表之后,双向链表就更好理解了
它的大致结构是这样子的:
那么就是设计一个结构体来表示节点,很多人都用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");
}
}
写完了,希望双向链表对你有帮助