单向KP双向链表
- 单向链表只可向一个方向遍历
查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。也可以提前把一个节点的位置另外保存起来,然后直接访问。 - 双向链表双向遍历
双向链表中不仅有指向后一个节点的指针,还有指向前一个节点的指针。第一个节点的”前连接”指向NULL,最后一个节点的”后连接”指向NULL。
这样可以从任何一个节点访问前一个节点,也可以访问后一个节点,以至整个链表。一般是在需要大批量的另外储存数据在链表中的位置的时候用。
有头节点KP无头节点链表
有头结点的链表相对无头结点的链表来说,主要体现在链表结点的增减上
如果没有头结点,链表的第一个结点的增减操作要和其他结点分开独立出来,而有了头结点后,链表的第一个结点的增删操作可以和后续的节点合并的一起,同理对于尾结点。在部分的访问判断操作链表第一个结点位置的特殊性也造成了增加头结点后程序的简明性(不用将第一个结点单独提出来操作处理)!
非循环KP循环链表
循环链表中第一个节点之前就是最后一个节点,反之亦然。循环链表的无边界使得在这样的链表上设计算法会比普通链表更加容易。对于新加入的节点应该是在第一个节点之前还是最后一个节点之后可以根据实际要求灵活处理,区别不大。
通过上面分析,我们可以发现,双向有头循环列表对于链表元素的操作是更方便的!!!所以,本篇将模拟实现这种链表的增删改查,方便大家理解。
链表的声明DList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef int DataType;
typedef struct DListNode
{
struct DListNode *next;
struct DListNode *prev;
DataType data;
}DListNode, *pDListNode, **ppDListNode;
void Test();
void DListInit(ppDListNode head);//初始化
void DListPushFront(ppDListNode head, DataType x);//头插
void DListPushBack(ppDListNode head, DataType x);//尾插
void DListPopFront(ppDListNode head);//头删
void DListPopBack(ppDListNode head);//尾删
void Insert(ppDListNode head, pDListNode pos, DataType x);//任意位置插
void Erase(ppDListNode head, pDListNode pos); //任意位置删
int DListSize(pDListNode head);//算节点数
int DListEmpty(pDListNode head);//判断是否为空
pDListNode DListFind(pDListNode head, DataType x);//查某个数所在节点位置
void DListRemove(ppDListNode head, DataType x);//删除第一个x
void DlistRemoveAll(ppDListNode head, DataType x);//删除x
void DListClear(ppDListNode haed);//清空
void DListDestory(ppDListNode head);//销毁
链表的功能实现DList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "DList.h"
pDListNode BuyDListNode(DataType x)//创建一个节点
{
pDListNode node = (pDListNode)malloc(sizeof(DListNode));
assert(node);
node->data = x;
node->prev = NULL;
node->next = NULL;
return node;
}
void DListInit(ppDListNode head)//初始化
{
assert(head);
int no_use = 0;
*head = BuyDListNode(no_use);
(*head)->next = *head;
(*head)->prev = *head;
}
void DListPushFront(ppDListNode head, DataType x)//头插
{
pDListNode node = BuyDListNode(x);
pDListNode first = (*head)->next;
assert(head);
(*head)->next = node;
node->prev = *head;
node->next = first;
first->prev = node;
//DListInsert(head,head->next,x);
}
void DListPushBack(ppDListNode head, DataType x)//尾插
{
pDListNode node = BuyDListNode(x);
pDListNode end = (*head)->prev;
assert(head);
node->next = *head;
(*head)->prev = node;
end->next = node;
node->prev = end;
//DListInsert(head,head,x);
}
void DListPopFront(ppDListNode head)//头删
{
pDListNode first = (*head)->next;
pDListNode node = first->next;
assert(head);
node = (*head)->next;
node->prev = *head;
free(first);
//DListErase(head,head->next);
}
void DListPopBack(ppDListNode head)//尾删
{
pDListNode end = (*head)->prev;
pDListNode node = end->prev;
assert(head);
node->next = *head;
(*head)->prev = node;
free(end);
//DListErase(head,head->prev);
}
void DListInsert(ppDListNode head,pDListNode pos,DataType x)//任意位置插
{
pDListNode node = BuyDListNode(x);
pDListNode cur = pos->prev;
assert(head);
cur->next = node;
node->prev = cur;
node->next = pos;
pos->prev = node;
}
void DListErase(ppDListNode head, pDListNode pos)//任意位置删
{
pDListNode node = pos->prev;
pDListNode cur = pos->next;
assert(head);
assert(pos != (*head));
node->next = cur;
cur->prev = node;
free(pos);
}
int DListSize(pDListNode head)//算节点数
{
size_t size = 0;
pDListNode node = head;
while (node->next != head)
{
node = node->next;
size++;
}
return size + 1;//算上头节点
}
int DListEmpty(pDListNode head)//判断是否为空
{
return head->next == head ? 1 : 0;
}
pDListNode DListFind(pDListNode head, DataType x)//查某个数所在节点位置
{
pDListNode node = head->next;
while (node != head)
{
if (node->data == x)
return node;
node = node->next;
}
return NULL;
}
void DListRemove(ppDListNode head, DataType x)//删除第一个x
{
pDListNode pos = DListFind(*head, x);
assert(head);
assert(pos != *head);
DListErase(head, pos);
}
void DlistRemoveAll(ppDListNode head, DataType x)//删除x
{
pDListNode node = (*head)->next;
while (node != *head)
{
if (node->data == x)
{
pDListNode cur = node->next;
pDListNode cur_new = node->prev;
cur_new->next = cur;
cur->prev=cur_new;
free(node);
node = cur;
}
else
node = node->next;
}
}
void DListClear(ppDListNode head)//清空
{
pDListNode node = (*head)->next;
assert(head);
while (node != *head)
{
pDListNode cur = node->next;
free(node);
node = cur;
}
(*head)->next = node;
node->prev = *head;
}
void DListDestory(ppDListNode head)//销毁
{
DListClear(head);
free(*head);
*head = NULL;
}
void DListPrint(pDListNode head)
{
pDListNode node = head->next;
printf("%2d ->", head->data);
while (node != head)
{
printf("%2d ->", node->data);
node = node->next;
}
printf("%2d\n", head->data);
}
测试代码
void Test()
{
DListNode *list = NULL;
DListInit(&list);
DListPushFront(&list, 1);//头插
DListPushFront(&list, 2);//头插
DListPushFront(&list, 3);//头插
DListPushFront(&list, 4);//头插
DListPrint(list);
DListPushBack(&list, 101);//尾插
DListPushBack(&list, 102);//尾插
DListPushBack(&list, 103);//尾插
DListPushBack(&list, 104);//尾插
DListPrint(list);
DListInsert(&list, list->next, 100);//任意位置插
DListPrint(list);
DListErase(&list, list->next);//任意位置删
DListPrint(list);
int ret = DListSize(list);//算节点数
printf("节点数%d\n", ret);
int cur = DListEmpty(list);//判断是否为空
if (cur == 1)
printf("链表为空\n");
else
printf("链表不为空\n");
DListInsert(&list,list->next->next,1);//任意位置插
DListPrint(list);
DListInsert(&list, list->next->next->next->next, 1);//任意位置插
DListPrint(list);
DListPushBack(&list, 1);//尾插
DListPushFront(&list, 1);//头插
DListPrint(list);
DlistRemoveAll(&list, 1);//删除x
DListPrint(list);
DListPushFront(&list, 1);//头插
DListPushFront(&list, 2);//头插
DListPushFront(&list, 3);//头插
DListPushFront(&list, 4);//头插
DListPrint(list);
DListRemove(&list, 1);//删除第一个x
DListPrint(list);
DListClear(&list);//清空
DListPrint(list);
DListDestory(&list);//销毁
}
主函数(main.c)
#define _CRT_SECURE_NO_WARNINGS 1
#include "DList.h"
int main()
{
Test();
system("pause");
return 0;
}