一、双链表
单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点依次顺序地向后遍历。
要访问某个结点的前驱结点(插入、删除操作时),只能从头开始遍历,访问后继结点的时间复杂度为0(1),访问前驱结点的时间复杂度为O(n)。
为了克服单链表的上述缺点,引入了双链表,双链表结点中有两个指针prior和next,分别指向其前驱结点和后继结点。
1.1 双链表的存储定义:
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior,*next;
}DNode,*DlinkList
双链表在单链表的结点中增加了一个指向其前驱的prior指针,因此双链表中的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操作的实现上,与单链表有着较大的不同。
1.2 双链表的初始化:
bool InitDLinklist(DlinkList l&){
L = (DNode *)malloc(sizeof(DNode));
if(L==NULL)
return false;
L->prior = NULL;
L->next = NULL;
return true;
}
1.3 双链表的判空:
bool Empty(DlinkList L){
if(L->next==NULL)
return true;
else
return false;
}
1.4 双链表的查找操作:
在带头结点的双向链表L中查找第i个元素,返回结点的地址。
DNode *GetElemP_DuL(DlinkList L, int i) {
int j;
DlinkList p;
p = L->next;
j = 1;
while (j<i&&p) {
p = p->next;
++j;
}
if (!p||j>i)
return NULL;
return p;
}
1.5 双链表的插入操作:
在L中确定第i个元素的位置指针p,进行前插或者后插。 【分析】:循环操作:在L中确定第i个元素的合法位置指针p;再创建s结点,把e赋给s的数据域。
1、后插核心代码:
s = new DNode;
s->data = e;
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
++length;
----
2、前插核心代码:
s = new DNode;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
++length;
----
3、在双向链表的第一个元素上插入
if(i==1){
s = new DNode;
s->data = e;
DlinkList p = L->next;
L->next = s;
s->prior = L;
s->next = p;
p->prior = s;
++length;
}
----
4、在双向链表的最后一个元素上插入
else if (i == length) {
s = new DNode;
s->data = e;
DlinkList p = L;
while (p->next)
p = p->next;
p->next = s;
s->prior = p;
s->next = NULL;
++length;
算法双向链表的插入: 在带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1<=i<=表长+1。
Status ListInsert_DuL(DlinkList &L, int i, ElenType e) {
DlinkList s, p;
if (!(p = GetElemP_DuL(L, i)))
return ERROR;
if (i == 1) {
s = new DNode;
s->data = e;
DlinkList p = L->next;
L->next = s;
s->prior = L;
s->next = p;
p->prior = s;
++length;
} else if (i == length) {
s = new DNode;
s->data = e;
DlinkList p = L;
while (p->next)
p = p->next;
p->next = s;
s->prior = p;
s->next = NULL;
++length;
} else {
s = new DNode;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
++length;
}
return true;
}
1.6 双链表的删除操作:
删除带头结点的双向链表L中第i个位置之前插入的元素e,i的合法值为1<=i<=表长。 【分析】:删除p结点,要解决p的前驱与后继指向问题!!
- 1、在L中确定元素e的位置i,指针p指向第i个位置;
- 2、满足:p的前驱的后继 == p的后继;
- 3、满足:p的后继的前驱 == p的前驱 。
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
--length;
删除带头结点的双向链表L中第i个位置之后插入的元素e,i的合法值为1<=i<=表长。 【分析】:删除p结点的后一个结点q,要解决q的前驱与后继指向问题!!
- 1、在L中确定元素e的位置i,指针p指向第i个位置;
- 2、满足:p下一个结点是q的下一个结点;
- 3、满足:q下一个结点的前驱是p结点。
bool DeleteNextDNode (DNode *p){
if (!(p = GetElemP_DuL(L, i)))
return ERROR;
DNode *q = p->next;
if (q==NULL)
return false;
p->next=q->next;
if (q->next!=NULL)
q->next->prior=p;
free(q);
return true;
}
|