目录
双向链表既有指向前驱的指针,又有指向后继的指针(也就是比单链表多一条从后往前的链)
定义结构如下:
//双向链表
typedef struct DNode
{
int data;//数据域
struct DNode* prio;//前驱指针
struct DNode* next;//后继指针
}DNode, * DList;
其初始化,求链表长度,按值查找,输出与单链表大同小异。
插入
头插
头插要连接的链从单链表的两个变成了四个
第一步还是先连后面的链
1.连后继:p->next = plist->next;
2.连后继的前驱指针:plist->next->prio = p
在这里用到了两个指针,以防plist->next为空导致错误,我们需要在这句话前面判断:如果plist->next!=NULL,才执行这条语句。(后面的如果用到多个指针都需要像这样先判断是否为空)
第二步连前面的链
3.plist->next = p;
4.p->prio = plist;
这样,四条线就连完了。
//头插
bool Insert_head(DList plist, int val)
{
assert(plist != NULL);
if (plist == NULL)
{
return false;
}
DNode* p = (DNode*)malloc(sizeof(struct DNode));//存
assert(p != NULL);
p->data = val;
p->next = plist->next;
if (plist->next != NULL)//判断很重要
{
plist->next->prio = p;
}
plist->next = p;
p->prio = plist;
return true;
}
尾插
尾插同理连四条,下面可以对比一下双向链表与单链表的区别
(左为双向链表,右为单链表)
在pos位置插入val
如果会了上面两种插入,按位置插也不难了
在pos位置插入和删除都要注意判断pos位置是否可以操作
//位置插
bool Insert(DList plist, int pos, int val)
{
assert(plist != NULL);
if (plist == NULL)
return false;
if (pos<0 || pos>GetLength(plist))
return false;
DNode* p = (DNode*)malloc(sizeof(struct DNode));
DNode* q = plist;
assert(p != NULL || q != NULL);
for (int i = 0; i < pos; i++)
{
q = q->next;
}
p->data = val;
p->next = q->next;
if (q->next != NULL)
q->next->prio = p;
p->prio = q;
q->next = p;
return true;
}
删除
删除第一个val值
定义两个节点指针p,q
找到val的前驱
p指向前驱,q指向要删除的那个
最后free掉它
(其实定义一个也可以,不过本人习惯定义两个)
//删除,第一个val值
bool DelVal(DList plist, int val)
{
assert(plist != NULL);
if (plist == NULL)
return false;
DNode* p;
DNode* q;
p = GetPrio(plist, val);//val的前驱
if (p == NULL)
return false;
q = p->next;
p->next = q->next;
if(q->next!=NULL)
q->next->prio = p;
free(q);
return true;
}
删除pos位置的值
//删除,pos位置的值
bool DelPos(DList plist, int pos)
{
assert(plist != NULL);
if (plist == NULL)
return false;
if (pos < 0 || pos >= GetLength(plist))
return false;
DNode* p = plist;
for (int i = 0; i < pos; i++)
{
p = p->next;
}
DNode* q;
q = p->next;
p->next = q->next;
if(q->next!=NULL)
q->next->prio = p;
free(q);
return true;
}