一、链表整体代码概述
- 链表的建立和各种操作建立在单个删除和单个添加的函数之上,一般来说只要写好了这两个基本的函数,其他的函数只要判断好添加和删除的条件再调用这两个基本的函数就好了。
- 除此之外,链表的内存问题依旧要注意…注意好释放的顺序就可以了。
- 链表、二叉树等,需要考虑的特殊情况基本都是根节点为NULL的情况、以及到链表末尾的情况,在单个删除和单个添加函数中另外建立pop_front,pop_back,push_front,push_back几个特殊情况的函数也是一个好办法的。
二、头文件概述
- 这个代码的是双向链表的。不过除了多一个prev指针的简单处理,和单向链表完全没有区别。
- 这里只收录node的声明和list类的private声明。
class list {
public:
typedef int data_type;
struct node {
public:
data_type data;
node* next;
node* prev;
node(data_type data = 0, node* next = NULL, node* prev = NULL)
: data(data), next(next), prev(prev){};
};
typedef node listNode;
typedef node* listPointer;
typedef unsigned int size_type;
private:
listPointer head;
listPointer tail;
size_type _size;
};
三、按条件删除代码
- 首先是按照条件删除某些节点的代码。
list& list::remove_if(bool (*condition)(listPointer)){
int i,pos=0; //pos代表从0位开始一个个检查是否符合条件condition
listPointer tmp=head;
while(tmp!=NULL){
if(condition(tmp)){
tmp=tmp->next;
erase(pos);//注意这时候pos不用++!因为删除了本位置的,
}else{ //后面的就顶替了这个位置
tmp=tmp->next;
pos++; //检查不符合条件,pos跳到下一位
}
}
return *this;
}
- 这里有意思的地方就在pos在什么时候要++,就像你在跑步比赛中超过了第二名,那你现在是第几名一样的问题。
在删除了目前位置的节点之后,后面的节点的位置就变成了目前的pos,再判断时就不用再++了;同理,如果这个位置不符合condition,那pos自然要++移到下一位。
接下来是erase的代码。
void list::erase(int position){
int i;
if(_size==0){
head=NULL;
tail=NULL;
return;
}
if(position>_size-1 || position<0)
return;
if(position==0){
pop_front();
return;
}
if(position==_size-1){
pop_back();
return;
}
listPointer tmp=head;
listPointer tmp1=tmp->next;
for(i=0;i<position-1;i++){
tmp=tmp->next;
tmp1=tmp1->next;
}
tmp1->next->prev=tmp;
tmp->next=tmp1->next;
delete tmp1;
_size--;
}
- 作为基本的操作的函数,可以把它分为两部分:判断条件,处理特殊情况(一般是对链表首尾的操作);一般情况的操作。由于这里是双向链表,所以多了设定prev指针的操作,其他和单向链表的想法并无二致。
- 之后的pop代码,再处理根节点的特殊情况。除了只有一个节点的时候设定这个节点同时为首尾之外,似乎没有什么需要注意的地方。
void list::pop_front(void){
if(empty())
return;
if(_size==1){
delete head;
head=NULL;
tail=NULL;
_size--;
return;
}
listPointer tmp=head;
head=head->next;
head->prev=NULL;
delete tmp;
_size--;
if(_size==1){
tail=head;
}
}
void list::pop_back(void){
if(empty())
return;
if(_size==1){
delete head;
head=NULL;
tail=NULL;
_size--;
return;
}
listPointer tmp=tail;
tail=tail->prev;
tail->next=NULL;
delete tmp;
_size--;
if(_size==1){
head=tail;
}
}
四、小总结
- 真头疼啊这次双向链表,检讨自己这次作业的几个错误:
- 1、因为没有注意到几个函数可以复用(我把他们认为是所谓基本函数),所以多写了很多重复的步骤,导致bug产生的几率也变大了。
- 2、就如同按条件删除中讲的,“超过第二名”这样的问题没有想清楚,所以整个链出现了:删除的size没有问题,但是删除错节点的问题。
- 3、在测试较大的数据的时候出现了输入流溢出的情况…困惑了许久。
- 待续。