前言:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
由图可知双向链表由头指针、尾指针和数据域组成。之前的单链表就只有一个指针和一个数据域,这也造成了单链表访问时只能从头开始,直到链表的结尾。而双向链表前后的有两个指针,既可以从头遍历到尾, 又可以从尾遍历到头,也就是一个节点既有向前连接的引用, 也有一个向后连接的引用。因此,双向链表可以有效的解决单向链表中提到的问题。
1.定义节点属性
struct Node
{
int data;
struct Node*front;
struct Node*tail;
};
2.创建一个有头的双向链表
struct Node*createList()
{
struct Node*headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->front = headNode;
headNode->tail = headNode;
return headNode;
}
3.创建一个节点
struct Node*createNode(int data)
{
struct Node*newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->front = NULL;
newNode->tail = NULL;
return newNode;
}
4.插入节点–>头插法
第一次插入时
void insertByHead(struct Node*list, int data)
{
struct Node*newNode = createNode(data);
if (list->tail != NULL)
{
//第一次是插入时,list->tail==NULL;
//所以尾节点指针不需要处理
newNode->tail = list->tail;
list->tail->front = newNode;
}
newNode->front = list;
list->tail = newNode;
}
5.指定位置插入
void inserteByAppion(struct Node*list, int data, int posData)
{
struct Node*posFrontNode = list;
struct Node*posNode = list->tail;
while (posNode != NULL&&posNode->data != posData)
{
posFrontNode = posNode;
posNode = posFrontNode->tail;
}
if (posNode == NULL)
{
printf("指定位置不存在,无法插入");
return;
}
else
{
struct Node*newNode = createNode(data);
newNode->tail = posNode;
posNode->front = newNode;
posFrontNode->tail = newNode;
newNode->front = posFrontNode;
}
}
6.表头法删除
void deleteByHead(struct Node*list)
{
if (list->tail != NULL)
{
struct Node*fristNode = list->tail;
list->tail = fristNode->tail;
if (fristNode->tail != NULL)
{
fristNode->tail->front = list;
}
free(fristNode);
}
}
7.指定位置删除
void deleteAppion(struct Node*list, int posData)
{
struct Node*posFrontNode = list;
struct Node*posNode = list->tail;
while (posNode->data != posData)
{
posFrontNode = posNode;
posNode = posFrontNode->tail;
}
if (posNode == NULL)
{
printf("抱歉,没有找到指定位置");
return;
}
else
{
posFrontNode->tail = posNode->tail;
if (posNode->tail != NULL)
{
posNode->tail->front = posFrontNode;
free(posNode);
}
}
}
8.表尾插入
void inserteByTail(struct Node*list, int data)
{
struct Node*tailNode = list;
while (tailNode->tail != NULL)
{
tailNode = tailNode->tail;
}
struct Node*newNode = createNode(data);
tailNode->tail = newNode;
newNode->front = tailNode;
}
9.表尾删除
void deleteByTail(struct Node*list)
{
struct Node*tailFrontNode = NULL;
struct Node*tailNode = list;
while (tailNode->tail != NULL)
{
tailFrontNode = tailNode;
tailNode = tailNode->tail;
}
//当链表只有表头时,不能做以下操作
if (tailFrontNode != NULL)
{
tailFrontNode->tail = NULL;
free(tailNode);
}
}
10.打印链表
void printList(struct Node*list)
{
struct Node*pMove = list->tail;
while (pMove != NULL)
{
printf("%d\t", pMove->data);
pMove = pMove->tail;
}
printf("\n");
}
测试代码
int main()
{
struct Node*list = createList();
for (int i = 0;i < 10;i++)
{
insertByHead(list, i);
}
printList(list);
deleteAppion(list, 4);
printList(list);
inserteByAppion(list, 4, 3);
printList(list);
inserteByTail(list, 89);
printList(list);
for (int i = 0;i < 10;i++)
{
deleteByTail(list);
}
printList(list);
system("pause");
return 0;
}
结果图:
总结: 双向链表的实现实际上与单链表的做法差不多,仅仅多了一个头节点指针需要处理,在实现头插法是得先判断后节点是否为空(即是否第一次插入),是则需要特殊处理,指定位置插入是,需要注意处理四个节点指针变量。赶紧动手试试吧…