数据结构学习笔记5——双链表
以下笔记为笔者复习时使用,仅供参考.
存储结构
双链表的存储结构同单链表类似,逻辑上相邻的元素,在内存中并不相邻,但是增加了一个前驱指针,指向上一个节点。
以不带头结点的双链表为例:
物理存储结构:
数据结构
双链表的数据结构定义如下:
typedef struct L_node
{
elem_t data;
struct L_node* pprior;//前驱指针
struct L_node* pnext;//后继指针
}DLinklist, * p_dlist;
基本操作
初始化
双链表的初始化
DLinklist InitDlinklist(p_dlist L)
{
L = (p_dlist)calloc(1, sizeof(DLinklist));//申请节点并初始化
if (NULL == L)
{
printf("memory is full\n");;//内存不足分配失败
}
return *L;
}
头插法、尾插法
//头插法
DLinklist Head_insert(p_dlist L_head, p_dlist L_tail)
{
int i;
while (scanf("%d", &i) != EOF)
{
p_dlist pnew = (p_dlist)calloc(1, sizeof(DLinklist));
pnew->data = i;
if (0 == L_head->data)
{//链表为空时,首尾指针指向pnew
L_head = pnew;
L_tail = pnew;
}
else
{//链表非空时,头插
pnew->pnext = L_head;
L_head->pprior = pnew;//更改前驱指针
L_head = pnew;
}
}
return *L_head;
}
//尾插法
DLinklist Tail_insert(p_dlist L_head, p_dlist L_tail)
{
int i;
while (scanf("%d",&i)!=EOF)
{
p_dlist pnew = (p_dlist)calloc(1, sizeof(DLinklist));
pnew->data = i;
if (0 == L_head->data)
{//链表为空时,首尾指针都指向新节点pnew
L_head = pnew;
L_tail = pnew;
}
else
{//链表非空时则尾插
L_tail->pnext = pnew;
pnew->pprior = L_tail;//新节点的前驱指针指向原链表的尾部
L_tail = pnew;
}
}
return *L_head;
}
以下是笔者写的有序插入(未测试),可用于参考思路
DLinklist Sort_insert(p_dlist L_head,p_dlist L_tail)
{
int i;
while (scanf("%d",&i)!=EOF)
{
p_dlist pnew = (p_dlist)calloc(1, sizeof(DLinklist));
p_dlist pcur, ppre;//定义两个哨兵,关羽(pcur)、张飞(ppre)
pcur = L_head;//让两个哨兵都指向头节点
ppre = pcur;
pnew->data = i;
if (0 == L_head->data)
{//链表为空时,首尾指针都指向新节点
L_head = pnew;
L_tail = pnew;
}
else if(pnew->data<L_head->data)
{//新节点的元素小于链表的第一个元素,头插
pnew->pnext = L_head;
L_head->pprior = pnew;
L_head = pnew;
}
else
{
while (pcur)
{//遍历链表
if (pnew->data < pcur->data)
{
//当新元素小于关羽(pcur),即大于张飞时,则插入
ppre->pnext = pnew;
pnew->pprior = ppre;
pnew->pnext = pcur;
pcur->pprior = pnew;
break;
}
//关羽(pcur)先走一步,张飞(ppre)紧随其后,遍历链表
ppre = pcur;
pcur = pcur->pnext;
}
if (NULL == pcur)
{//遍历到链表尾部,则尾插
L_tail->pnext = pnew;
pnew->pprior = L_tail;
L_tail = pnew;
}
}
}
return *L_head;
}
删除
DLinklist List_delete(p_dlist L_head, p_dlist L_tail)
{//未测试
int i;
while (scanf("%d",&i)!=EOF)
{
p_dlist pcur, ppre;
pcur = L_head;
ppre = pcur;
if (0 == L_head->data) //初始化后0为空,亦或者 if(NULL==L_head->data)
{
printf("The list is empty\n");
}
else if (i == L_head->data)
{//删除的节点是头节点
L_head = pcur->pnext;
free(pcur);
pcur = NULL;
if (0 == L_head->data)//if(NULL==L_tail)
{//删除的节点是最后一个节点
L_tail = NULL;
L_head = NULL;
}
}
else
{//删除的节点是中间节点
while (pcur)
{
if (i == pcur->data)
{
ppre->pnext = pcur->pnext;
pcur->pnext->pprior = ppre;
free(pcur);
pcur = NULL;
break;
}
ppre = pcur;
pcur = pcur->pnext;
}
if (NULL == pcur)
{//删除的节点是尾节点
L_tail = ppre;
}
}
}
return *L_head;
}
查找
按位序查找和按值查找,代码如下:
int List_find(p_dlist L_head, p_dlist L_tail)
{//按位序查找
int cnt = 0;
int i;
if (NULL == L_head)
{
fprintf(stderr, "error:The list is empty\n");
return 0;
}
printf("Input the num you want to find:\n");
scanf("%d", &i);
while (L_head)
{
if (i == L_head->data)
{
break;
}
L_head = L_head->pnext;
cnt++;
}
return cnt;
}
bool List_locate(p_dlist L_head)
{//按值查找
int i;
p_dlist pcur = L_head;
if (NULL == L_head)
{
fprintf(stderr, "Error:The list is empty\n");
return false;
}
printf("Input the num you want to find:\n");
scanf("%d", &i);
while (pcur)
{
if (i == pcur->data)
{
printf("The number you find is:%d\n", pcur->data);
return true;
}
pcur = pcur->pnext;
}
}
销毁
void List_Destory(p_dlist L_head)
{//带头结点的链表销毁
while (L_head->pnext!=NULL)//遍历链表
{
if (NULL == L_head)
{
printf("The List is empty\n");
}
p_dlist pcur = L_head->pnext;
if (NULL == pcur)
{//链表只有一个节点的情况
printf("The List doesn't has next node\n");
}
L_head->pnext = pcur->pnext;
if (pcur->pnext != NULL)//pcur不是最后一个节点
{//释放节点空间
pcur->pnext->pprior = L_head;
}
free(pcur);
}
free(L_head);
L_head = NULL;
}
本文思维导图大致如下:
笔者个人能力有限,不足之处请给予指正。