一开始我就觉得双向链表非常非常的麻烦,但是老师出了一道上机题。debug了好久才过(博主比较菜还请大家见谅),所以贴出来共享下。
链表比较麻烦的就是插入和删除操作。一定要先弄懂指针到底是指向哪里的。
我们首先用结构体struct 定义了node,node中包括了data(这个结点存的数据),*prev(指向上一个节点的指针)和*next(指向下一个节点的指针)
我在构造函数中首先新建了头尾结点,于是插入删除操作可以避免边界的讨论。
插入时,我们假定要在A结点和B结点中插入C结点,那么首先我们要新建一个节点(我用的是new),(假设我们用temp指针指向这个新的结点)然后我们把要存的元素复制给data,所以我们让temp -> data(令temp指针指向data),在把元素复制给data。 在c++ 中就是 entry(我们要存的元素) = temp -> data。然后我们令temp -> next = B, temp -> prev = A,那么C的下一个节点就是B,上一个节点就是A。
然后我们要把c结点插入A结点和B结点之间,所以我们用setPosition函数让*current 指向A结点, 那么current -> next 就会指向B结点。这时候我们要注意赋值的顺序。我们首先把current -> next -> prev = C(表示A结点的下一个节点的上一个节点,也就是B结点的上一个节点),于是B结点的prev就会指向C结点,所以B结点的上一个就会变成C结点。同理我们current -> next = C,把A的下一个节点变成了C,于是我们就完成插入插入操作。// 一定要注意current的赋值顺序。
删除操作同理,首先用setPosition找到要删除的结点。这是我们要定义多一个临时的指针temp来存这个结点(否则如果我们没有delete的话,这个结点没有指针指向它,会变成内存垃圾,如果我们delete current的话会整个链表就没有指针可以访问了,所以我们在完成操作之后要delete temp来避免这些问题)如果怕删除出错的话可以定义*p = current -> prev, *q = current -> next,用p,q指针分别指向要删除结点的前一个结点和后一个结点。然后我们让p -> next = q, q -> prev = p就可以了,如果嫌这个麻烦也可以直接 current -> next -> prev = current -> prev; current -> prev -> next = current -> next; 最后我们可以让current = current -> next 或者current = current -> prev,最后delete掉temp,完成删除操作。
这份代码的函数是老师给定好的,private用了current指针而没有用head 和 而且加了curPosition. (因为如果用head的话速度会慢一点,因为插入等函数要从head开始遍历,所以每次遍历到当前的position需要 position - 1次,而如果用curPosition的话就会快一点// 因为current函数到Posiiton的距离一定比head 到Position的距离短 // 如果是连续插入的话,那么curPosition到下一个节点的距离为1,而head到position的距离就是 position -1 所以用current会快)
还有就是由于有insert(插入),和retrieve(获得position位置的元素)函数,所以我在深复制的时候直接用了insert和retrieve。
以下是代码
#include <iostream> #include <cstdlib> using namespace std; enum Error_code { success, underflow, overflow }; template <class List_entry> struct Node { List_entry entry; Node<List_entry> *next; Node<List_entry> *back; }; template <class List_entry> class MyList { public: MyList() { count = 0; curPosition = -1; current = new Node<List_entry>;// head current -> entry = -1; current -> next = new Node<List_entry>; // tail current -> next -> entry = -1; current -> back = NULL; current -> next -> back = current; current -> next -> next = NULL; } ~MyList() { clear(); Node<List_entry>*p = current, *q = current -> next; // 头结点和尾结点不能在clear里面删除,否则会出现clear后在insert的时候就没有头尾结点了 delete p; delete q; current = NULL; } // 拷贝构造函数和赋值运算符重载,注意深拷贝与浅拷贝的差异 MyList(const MyList<List_entry> ©) { count = 0; curPosition = -1; current = new Node<List_entry>;// head current -> entry = -1; current -> next = new Node<List_entry>; // tail current -> next -> entry = -1; current -> back = NULL; current -> next -> back = current; current -> next -> next = NULL; List_entry entry; while (count < copy.size()) { copy.retrieve(count, entry); insert(count, entry); } setPosition(copy.curPosition); } void operator =(const MyList<List_entry> ©) { count = 0; curPosition = -1; current = new Node<List_entry>;// head current -> entry = -1; current -> next = new Node<List_entry>; // tail current -> next -> entry = -1; current -> back = NULL; current -> next -> back = current; current -> next -> next = NULL; List_entry entry; while (count < copy.size()) { copy.retrieve(count, entry); insert(count, entry); } setPosition(copy.curPosition); } // 清空list void clear() { List_entry entry; while (size()) { remove(count - 1,entry); } count = 0; } // 判断list是否为空 bool empty() const { return (count == 0) ? 1 : 0; } // 判断list是否已满 bool full() const { return false; } // 获取list的元素数量 int size() const { return count; } // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推 // 若position < 0 或者 position > count,则返回underflow Error_code insert(int position, const List_entry &entry) { if (position < 0 || position > count) return underflow; Node<List_entry>*p = new Node<List_entry>; p -> entry = entry; setPosition(position - 1); p -> next = current -> next; p -> back = current; current -> next -> back = p; current -> next = p; count++; return success; } // 删除第position个位置的元素,并将该元素的值保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code remove(int position, List_entry &entry) { if (position < 0 || position >= count) return underflow; setPosition(position); Node<List_entry> *p = current; entry = p -> entry; p -> next -> back = p -> back; p -> back -> next = p -> next; current = current -> next; delete p; count--; return success; } // 获取第position个位置的元素,保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code retrieve(int position, List_entry &entry) const { if (position < 0 || position >= count) return underflow; setPosition(position); entry = current -> entry; return success; } // 将第position个位置的元素替换为entry // 若position < 0 或者 position >= count,则返回underflow Error_code replace(int position, const List_entry &entry) { if (position < 0 || position >= count) return underflow; setPosition(position); current -> entry = entry; return success; } // 用visit函数遍历list内所有的元素 void traverse(void (*visit)(List_entry &)) { for (int i = 0; i < size(); i++) { setPosition(i); visit(current -> entry); } } protected: int count; // 记录list内元素数量 mutable int curPosition; // current指针的位置编号 mutable Node<List_entry> *current; // current指针 // 设置current指针的位置,指向第position个位置 void setPosition(int position) const { if (position > curPosition) for (; curPosition < position; curPosition++) current = current -> next; else if (position < curPosition) for (; curPosition > position; curPosition--) current = current -> back; } };
链表比较复杂,所以博主啰嗦了一些,如果各位有更好的方法,还请指导,谢谢大家了。