本文部分内容来自于公众号技术让梦想更伟大
双链表
单链表是指结点中只有一个指向其后继的指针,具有单向性,但是有时需要搜索大量数据的时候,就需要多次进行从头开始的遍历,这样的搜索就不是很高效了。
在单链表的基础上,对于每一个结点设计一个前驱结点,前驱结点与前一个结点相互连接,构成一个链表,就产生了双向链表的概念了。
双向链表可以简称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
1、双链表节点的设计
其中,DATA表示数据,其可以是简单的类型也可以是复杂的结构体;
pre代表的是前驱指针,它总是指向当前结点的前一个结点,
next代表的是后继指针,它总是指向当前结点的下一个结点。
其代码实现如下:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
typedef struct listNode
{
int data;
struct listNode *next;
struct listNode *previous;
}linklist,*linkptr;
2、双链表的创建
创建双向链表 需要先创建头结点,将头节点的前驱、后继指针设置为NULL,并且返回节点指针,此时节点就创建好了。
linkptr link_create(void)
{
linkptr list;
if ((list = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n",__FILE__,__LINE__);
return NULL;
}
list->next = list->previous = NULL;
return list;
}
3、节点的插入
3.1、直接在尾部进行插入
由于双链表头节点可以有数据,所以这里我将头节点的前驱指针指向了自身。用来区分头节点和其他节点的不同,因为我是先创建了头节点(linkptr link_create(void))。然后在在另一个函数进行节点的插入(void link_insert(linkptr list,int value))。如果节点的前驱指针与后继指针都是NULL,证明此时链表只有一个空的头节点。
void link_insert(linkptr list,int value)
{
linkptr new_node;
if ((list->next == NULL)&&(list->previous == NULL))
{
list->data = value;
list->previous = list;
return ;
}
if ((new_node = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n",__FILE__,__LINE__);
return ;
}
new_node->next = new_node->previous = NULL;
new_node->data = value;
while (list->next)
{
list = list->next;
}
list->next = new_node;
new_node->previous = list;
new_node->next = NULL;
}
3.2、指定位置进行插入
void link_insert_local(linkptr list, int local,int value)
{
linkptr new_node;
int j = 0;
if ((new_node = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n", __FILE__, __LINE__);
return;
}
while (j < local)
{
j+=1;
list = list->next;
}
new_node->data = value;
new_node->next = new_node->previous = NULL;
if (list->next == NULL)
{
list->next = new_node;
new_node->previous = list;
new_node->next = NULL;
return;
}
new_node->next = list->next;
list->next->previous = new_node;
list->next = new_node;
new_node->previous = list;
}
4、双链表的遍历
这里不能写list->next,因为最后一个节点的next指针为NULL。
void link_show(linkptr list)
{
while (list)
{
printf(" %d ", list->data);
list = list->next;
}
}
5、双链表的删除
删除操作的过程是:选择需要删除的结点->选中这个结点的前一个结点->将前一个结点的next指针指向自己的下一个结点->选中该节点的下一个结点->将下一个结点的pre指针修改指向为自己的上一个结点。
在进行遍历的时候直接将这一个结点给跳过了,之后,我们释放删除结点,归还空间给内存,
void link_delete(linkptr list,int local)
{
int j = 0;
while (j < local)
{
j+=1;
list = list->next;
}
list->previous->next = list->next;
list->next->previous = list->previous;
free(list);
}
6、源码
#include "stdio.h"
#include "stdlib.h"
typedef struct listNode
{
int data;
struct listNode *next;
struct listNode *previous;
} linklist, *linkptr;
linkptr link_create(void)
{
linkptr list;
if ((list = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n", __FILE__, __LINE__);
return NULL;
}
list->next = list->previous = NULL;
return list;
}
void link_insert(linkptr list, int value)
{
linkptr new_node;
if ((list->next == NULL) && (list->previous == NULL))
{
list->data = value;
list->previous = list;
return;
}
if ((new_node = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n", __FILE__, __LINE__);
return;
}
new_node->next = new_node->previous = NULL;
new_node->data = value;
while (list->next)
{
list = list->next;
}
list->next = new_node;
new_node->previous = list;
new_node->next = NULL;
}
void link_show(linkptr list)
{
while (list)
{
printf(" %d ", list->data);
list = list->next;
}
}
void link_insert_local(linkptr list, int local,int value)
{
linkptr new_node;
int j = 0;
if ((new_node = (linkptr)malloc(sizeof(linklist))) == NULL)
{
printf("%s %d:malloc error\n", __FILE__, __LINE__);
return;
}
while (j < local)
{
j+=1;
list = list->next;
}
new_node->data = value;
new_node->next = new_node->previous = NULL;
if (list->next == NULL)
{
list->next = new_node;
new_node->previous = list;
new_node->next = NULL;
return;
}
new_node->next = list->next;
list->next->previous = new_node;
list->next = new_node;
new_node->previous = list;
}
void link_delete(linkptr list,int local)
{
int j = 0;
while (j < local)
{
j+=1;
list = list->next;
}
list->previous->next = list->next;
list->next->previous = list->previous;
free(list);
}
int main(void)
{
linkptr link;
link = link_create();
printf("\n||----------插入数据测试(10,20,30)--------------||\n");
link_insert(link, 10);
link_insert(link, 20);
link_insert(link, 30);
link_show(link);
printf("\n||------插入节点测试(在第一个节点(0开始)后面插入66)----------||\n");
link_insert_local(link,1,66);
link_show(link);
printf("\n||------删除节点测试(删除第2个节点,就是data=66)----------||\n");
link_delete(link,2);
link_show(link);
return 0;
}
|