线性表—双链表
由于单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点依次顺序地向后遍历。访问后继结点的时间复杂度为O(1),访问前驱节点的时间复杂度为O(n)。
为了克服单链表的上述缺点,引入了双链表,双链表结点中有两个指针prior和next,分别指向其前驱节点和后继结点,使得访问前后结点的时间复杂度都为O(1)。
双链表中的结点类型描述如下:
typedef struct DNode {
Elemtype data;
struct DNode* prior, * next;
}DNode,*DLinkList;
初始化双链表:
DLinkList InitList(DLinkList& L) {
L = new DNode;//头结点
L->next = NULL;//头结点的后继结点置空
L->prior = NULL;//头结点的前驱结点置空
return L;
}
头插法创建链表:
DLinkList DList_HeadInsert(DLinkList& L) {
cout << "采用头插法建立双链表:" << endl;
InitList(L);
int x;
cin >> x;
while (x != 9999) {
DNode* s = new DNode;//申请新的结点
s->data = x;
//向链表头部插入结点s
s->next = L->next;
if (L->next != NULL) {
L->next->prior = s;
}
s->prior = L;
L->next = s;
cin >> x;
}
return L;
}
尾插法创建链表:
DLinkList DList_TailInsert(DLinkList& L) {
cout << "采用尾插法建立双链表" << endl;
InitList(L);
DNode* r = L;//申请一个新的结点*r,*r为尾结点
int x;
cin >> x;
while (x != 9999) {
DNode* s = new DNode;
s->data = x;
r->next = s;
s->prior = r;
r = s;
cin >> x;
}
r->next = NULL;//尾结点置为空
return L;
}
按位插入操作
bool ListInsert(DLinkList& L, int i, Elemtype e) {
if (i < 1) {//插入的i小于1,不合法
return false;
}
DNode* p = L;
DNode* s = new DNode;//申请一个新的结点
int j = 0;
while (j < i - 1 && p->next != NULL) {//找到第i-1个结点
p = p->next;
j++;
}
if (p == NULL) {
return false;
}
//插入操作
s->data = e;
s->next = p->next;
if (p->next != NULL) {
p->next->prior = s;
}
s->prior = p;
p->next = s;
return true;
}
按位查找操作:
bool GetElem(DLinkList L, int i) {
if (i < 1) {
return false;
}
DNode* s = new DNode;
s = L;
int j = 0;
while (j < i - 1 && s != NULL) {
s = s->next;
j++;
}
if (s == NULL) {
return false;
}
cout << s->next->data << endl;
return true;
}
按值查找操作:
int LocatElem(DLinkList& L, Elemtype e) {
DNode* s = new DNode;
int j = 0;
s = L;
while (s->data != e && s != NULL) {
s = s->next;
j++;
if (s == NULL) {
return 0;
}
}
return j;
}
按位删除操作
bool ListDelete(DLinkList& L, int i, Elemtype& e) {
if (i < 1) {
return false;
}
DNode* s = new DNode;
DNode* p;//*p为需要删除的结点
s = L;
int j = 0;
while (j < i - 1 && s != NULL) {//找到第i-1个结点
s = s->next;
j++;
}
if (s == NULL) {
return false;
}
else {
p = s->next;
if (p == NULL) {
return false;
}
//将*p从链中断开
e = p->data;
s->next = p->next;
if (s->next != NULL) {
s->next->prior = s;
}
free(p);//释放结点的存储空间
return true;
}
}
遍历操作:
bool PrintList(DLinkList L) {
DNode* s = L->next;
while (s != NULL) {
cout << s->data << "\t";
s = s->next;
}
cout << endl;
return true;
}
判空操作:
bool Empty(DLinkList L) {
if (L->next == NULL) {
return true;
}
return false;
}
销毁操作:
与删除操作有点类似
void DestoryList(DLinkList& L) {
DNode* p, * q;
p = L;
while (p-> next != NULL) {
q = p->next;
p->next = q->next;
if (q->next != NULL) {
p->next->prior = p;
}
free(q);
}
}
求表长:
int Length(DLinkList L) {
int j = 0;
DNode* s = new DNode;
s = L;
while (s->next != NULL) {
s = s->next;
j++;
}
return j;
}
以上是双链表需要用到的基本操作,时间复杂度均为O(n)。