这篇的代码不是自己写的是参考来的,虽然原博主代码写得不是很规范,但是基本思路是正确的,可作为学习的材料。原博地址 http://blog.csdn.net/cyp331203/article/details/42388065
———————————————————————————————————————————————————
不带哨兵节点的双向链表即一般的双向链表,有一个头指针指向第一个节点,每个节点有key值和两个指针next和pre,分别指向前后相邻的节点,头结点的pre=NULL,尾节点的next=NULL,比较明了,但是也有麻烦的地方:在做查找删除节点等操作的时候,免不了要判断边界条件,比如node==NULL等。先来看看这种链表的代码:
- /*
- * 实现没有哨兵节点的双向链表,需要自己判断边界条件
- */
- #include <iostream>
- using namespace std;
- class list {
- struct node {
- int key;
- node* next;
- node* pre;
- node(int k) :
- key(k), next(NULL), pre(NULL) {
- }
- };
- public:
- node* head;
- int len;
- list() :
- head(NULL), len(0) {
- }
- ~list() {
- node* tmp1 = head, *tmp2;
- while (tmp1 != NULL) {
- tmp2 = tmp1->next;
- delete tmp1;
- len--;
- cout << "len=" << len << endl;
- tmp1 = tmp2;
- }
- }
- /*
- * 在头处插入节点
- */
- void insertHead(int k) {
- node* n = new node(k);
- n->next = head;
- head = n;
- if (n->next != NULL) {
- n->next->pre = n;
- }
- len++;
- }
- /*
- * 删除指针指向的节点
- */
- int del(node* n) {
- if (n == NULL) {
- return -1;
- }
- if (n->pre != NULL) {
- n->pre->next = n->next;
- } else {
- head = n->next;
- }
- if (n->next != NULL) {
- n->next->pre = n->pre;
- }
- delete n;
- len--;
- return n->key;
- }
- /*
- * 查找具有某个key值的节点
- */
- node* searchList(int k) {
- if (len == 0) {
- return NULL;
- }
- node* tmp = head;
- while (tmp != NULL) {
- if (tmp->key == k) {
- break;
- }
- tmp = tmp->next;
- }
- return tmp;
- }
- /*
- * 遍历list
- */
- void travelList() {
- node* tmp = head;
- while (tmp != NULL) {
- cout << tmp->key << ' ';
- tmp = tmp->next;
- }
- cout << endl;
- }
- };
- int main() {
- list* l = new list();
- l->insertHead(5);
- l->insertHead(4);
- l->insertHead(3);
- l->travelList();
- l->del(l->head->next);
- l->travelList();
- delete l;
- return 0;
- }
/*
* 实现没有哨兵节点的双向链表,需要自己判断边界条件
*/
#include <iostream>
using namespace std;
class list {
struct node {
int key;
node* next;
node* pre;
node(int k) :
key(k), next(NULL), pre(NULL) {
}
};
public:
node* head;
int len;
list() :
head(NULL), len(0) {
}
~list() {
node* tmp1 = head, *tmp2;
while (tmp1 != NULL) {
tmp2 = tmp1->next;
delete tmp1;
len--;
cout << "len=" << len << endl;
tmp1 = tmp2;
}
}
/*
* 在头处插入节点
*/
void insertHead(int k) {
node* n = new node(k);
n->next = head;
head = n;
if (n->next != NULL) {
n->next->pre = n;
}
len++;
}
/*
* 删除指针指向的节点
*/
int del(node* n) {
if (n == NULL) {
return -1;
}
if (n->pre != NULL) {
n->pre->next = n->next;
} else {
head = n->next;
}
if (n->next != NULL) {
n->next->pre = n->pre;
}
delete n;
len--;
return n->key;
}
/*
* 查找具有某个key值的节点
*/
node* searchList(int k) {
if (len == 0) {
return NULL;
}
node* tmp = head;
while (tmp != NULL) {
if (tmp->key == k) {
break;
}
tmp = tmp->next;
}
return tmp;
}
/*
* 遍历list
*/
void travelList() {
node* tmp = head;
while (tmp != NULL) {
cout << tmp->key << ' ';
tmp = tmp->next;
}
cout << endl;
}
};
int main() {
list* l = new list();
l->insertHead(5);
l->insertHead(4);
l->insertHead(3);
l->travelList();
l->del(l->head->next);
l->travelList();
delete l;
return 0;
}
每次判断边界条件,虽然不会从根本上增加时间复杂度,但是对其常数项还是有影响的;而如果使用带哨兵节点构成的双向循环链表,则可以省去这些问题。我们使用一个“哑的”NIL节点来代替之前的head头指针,NIL节点的key值没有实际的意义,主要关注它的next和pre,初始的时候,链表只有一个NIL节点,NIL.next指向自己,NIL.pre也指向自己。当添加了若干个节点之后,NIL.next指向头节点,而NIL.pre则指向尾节点;而同样的,这时头节点的pre不再是NULL而是指向NIL,尾节点的next也不再是NULL,也是指向NIL。
这样的好处在于,我们判断边界条件的时候,不需要再判断是否为空,尤其在删除节点的时候,只需要写两句即可。但是这样也带来一些问题,就是要额外分配空间来存储NIL节点,如果对于多个比较短的链表而言,这样可能会代码比较大的冗余空间。
代码如下:
- /*
- * 实现带哨兵是双向循环链表
- */
- #include <iostream>
- using namespace std;
- class list {
- struct node {
- int key;
- node* next;
- node* pre;
- node(int k) :
- key(k), next(NULL), pre(NULL) {
- }
- };
- // node* head;
- public:
- node* nil; //哨兵节点
- int len;
- list() :
- nil(), len(0) {
- nil = new node(0); //初始化哨兵节点
- //让链表循环起来
- nil->next = nil;
- nil->pre = nil;
- }
- ~list() {
- //析构的时候要delete掉还存在于list中的节点
- if (len == 0) {
- delete nil;
- return;
- }
- node* n1 = nil->next;
- node* n2 = NULL;
- while (n1 != NULL && n1 != nil) {
- n2 = n1->next;
- delete n1;
- len--;
- n1 = n2;
- }
- delete nil;
- }
- /*
- * 在头部插入节点
- */
- void insertHead(int k) {
- node* n = new node(k);
- n->next = nil->next;
- n->pre = nil;
- nil->next = n;
- //这一句不要丢了
- n->next->pre = n;
- len++;
- }
- /*
- * 删除节点,这里删除的操作只需要写两句,比不带哨兵的链表操作要简洁的多
- */
- void del(node* n) {
- n->pre->next = n->next;
- n->next->pre = n->pre;
- delete n;
- len--;
- }
- node* searchList(int k) {
- node* tmp = nil->next;
- //让nil的key值永远不可能等于k
- // nil->key = k + 1;
- // while (tmp->key != k) {
- while (tmp != nil && tmp->key != k) {
- tmp = tmp->next;
- }
- if (tmp != nil) {
- return tmp;
- } else {
- return NULL;
- }
- }
- /*
- * 从next指针方向遍历链表
- */
- void travelClockwise() {
- node* tmp = nil->next;
- while (tmp != nil) {
- cout << tmp->key << ' ';
- tmp = tmp->next;
- }
- cout << endl;
- }
- /*
- * 从pre指针方向遍历链表
- */
- void travelAnticlockwise() {
- node* tmp = nil->pre;
- while (tmp != nil) {
- cout << tmp->key << ' ';
- tmp = tmp->pre;
- }
- cout << endl;
- }
- };
- int main() {
- list* l = new list();
- l->insertHead(5);
- l->insertHead(4);
- l->insertHead(3);
- l->travelClockwise();
- l->del(l->nil->pre);
- // l->travelClockwise();
- l->travelAnticlockwise();
- return 0;
- }
/*
* 实现带哨兵是双向循环链表
*/
#include <iostream>
using namespace std;
class list {
struct node {
int key;
node* next;
node* pre;
node(int k) :
key(k), next(NULL), pre(NULL) {
}
};
// node* head;
public:
node* nil; //哨兵节点
int len;
list() :
nil(), len(0) {
nil = new node(0); //初始化哨兵节点
//让链表循环起来
nil->next = nil;
nil->pre = nil;
}
~list() {
//析构的时候要delete掉还存在于list中的节点
if (len == 0) {
delete nil;
return;
}
node* n1 = nil->next;
node* n2 = NULL;
while (n1 != NULL && n1 != nil) {
n2 = n1->next;
delete n1;
len--;
n1 = n2;
}
delete nil;
}
/*
* 在头部插入节点
*/
void insertHead(int k) {
node* n = new node(k);
n->next = nil->next;
n->pre = nil;
nil->next = n;
//这一句不要丢了
n->next->pre = n;
len++;
}
/*
* 删除节点,这里删除的操作只需要写两句,比不带哨兵的链表操作要简洁的多
*/
void del(node* n) {
n->pre->next = n->next;
n->next->pre = n->pre;
delete n;
len--;
}
node* searchList(int k) {
node* tmp = nil->next;
//让nil的key值永远不可能等于k
// nil->key = k + 1;
// while (tmp->key != k) {
while (tmp != nil && tmp->key != k) {
tmp = tmp->next;
}
if (tmp != nil) {
return tmp;
} else {
return NULL;
}
}
/*
* 从next指针方向遍历链表
*/
void travelClockwise() {
node* tmp = nil->next;
while (tmp != nil) {
cout << tmp->key << ' ';
tmp = tmp->next;
}
cout << endl;
}
/*
* 从pre指针方向遍历链表
*/
void travelAnticlockwise() {
node* tmp = nil->pre;
while (tmp != nil) {
cout << tmp->key << ' ';
tmp = tmp->pre;
}
cout << endl;
}
};
int main() {
list* l = new list();
l->insertHead(5);
l->insertHead(4);
l->insertHead(3);
l->travelClockwise();
l->del(l->nil->pre);
// l->travelClockwise();
l->travelAnticlockwise();
return 0;
}