双向链表也叫双链表,是链表的一种,它的每一个数据结点中都有两个指针,分别指向直接后继和直接前驱。因此,从双向链表中的任意一个结点开始,均可以很方便地访问它的前驱结点和后继结点。ios
通常咱们都构造双向循环链表,由于双向链表解决了单向链表的不足和问题,而单链表由于出现的问题多,因此在面试中常常会考到单链表的问题。面试
在这里,我用 .cpp对双向链表的基本操做进行实现。ide
具体代码以下:函数
List.h文件:
测试
#pragma once typedef int DataType; struct ListNode //所有用做公有的就定义为struct,用做私有就定义class { //固然用class,写在public中也能够 DataType _data; ListNode* _next; //前驱指针 ListNode* _prev; //后继指针 ListNode(DataType x) //构造函数 :_data(x) ,_next(NULL) ,_prev(NULL) {} }; class List { public: List() :_head(NULL) ,_tail(NULL) {} ~List() { Clear(); } public: void PushBack(DataType x) { if(_head == NULL) { _head = _tail = new ListNode(x);//调用构造函数 } else { ListNode* tmp = new ListNode(x); _tail->_next = tmp; tmp->_prev = _tail; _tail = tmp; } } void PopBack() { //没有节点 //一个节点 //一个以上节点 if(_head == NULL) { return; } else if(_head == _tail) { delete _head; _head = _tail = NULL; } else { ListNode* cur = _tail->_prev; delete _tail; _tail = cur; cur->_next = NULL; } } void PushFront(DataType x) { if(_head == NULL) { _head = _tail = new ListNode(x); } else { ListNode* tmp = new ListNode(x); tmp->_next = _head; _head = tmp; } } void PopFront() { if(_head == NULL)//空 { return; } else if(_head == _tail)//一个节点 { delete _head; _head = _tail = NULL; } else //一个以上节点 { ListNode* del = _head; _head = _head->_next; _head->_prev = NULL; delete del; } } void Insert(ListNode* pos,DataType x) { assert(pos); if(pos == _tail) { PushBack(x); } else { /* ListNode* tmp = new ListNode(x); tmp->_next = pos->_next; pos->_next->_prev = tmp; //使用这种两个指针的方式虽然能够达到目的,可是容易出现问题 pos->_next = tmp; //首先得考虑pos是否为空,其次若pos->_next为空,再想找到它的prev就会出错 tmp->_prev = pos; */ ListNode* tmp = new ListNode(x);//这样定义两个指针保存先后的节点,就不容易出错 ListNode* next = pos->_next; tmp->_next = next; next->_prev = tmp; pos->_next = tmp; tmp->_prev = pos; } } ListNode* Find(DataType x) { if(_head == NULL) { return NULL;//找不到返回空 } else { ListNode* cur = _head; while(cur) { if(cur->_data == x) { return cur; } cur = cur->_next; } } } void Erase(ListNode* pos) { assert(_head); assert(pos); if(pos == _head)//删除头节点 { PopFront(); /* ListNode* del = _head; _head = _head->_next; _head->_prev = NULL; delete del; */ } else if(pos == _tail)//删除尾节点 { PopBack(); } else // 删除非头尾节点 { /* ListNode* cur = pos->_prev; cur->_next = pos->_next; pos->_next->_prev = cur; delete pos; */ ListNode* prev = pos->_prev; ListNode* next = pos->_next; prev->_next = next; next->_prev = prev; delete pos; } } void PrintList()//在此用不上前驱节点prev { ListNode* cur = _head; while(cur) { cout<<cur->_data<<"->"; cur = cur->_next; } cout<<"NULL"<<endl; } void Clear() { ListNode* cur = _head; while(cur) { ListNode* del = cur; cur = cur->_next; delete del; } } //翻转双向链表 void reverse() { /* ①.交换值 ListNode* begin = _head; ListNode* end = _tail; while(begin != end && begin->_prev != end)//当两个指针相遇或者已经偏离中止 { swap(begin->_data , end->_data); begin = begin->_next; end = end ->_prev; } */ //②.交换指针 ListNode* cur = _head; while(cur) { swap(cur->_prev , cur->_next);//把每一个节点的先后指针交换 cur = cur->_prev; } swap(_head,_tail); } private: ListNode* _head; ListNode* _tail; }; void Test() { List l; l.PushBack(1); l.PushBack(2); l.PushBack(3); l.PushBack(4); l.PushBack(5); l.PrintList(); l.PopBack(); l.PrintList(); l.PushFront(0); l.PrintList(); l.PopFront(); l.PrintList(); l.Insert(l.Find(1),0); l.PrintList(); l.Erase(l.Find(1)); l.PrintList(); l.reverse(); l.PrintList(); }
List.cpp 文件:(测试)spa
#include<iostream> #include<assert.h> using namespace std; #include "DoubleSList.h" //双向链表 int main() { Test(); return 0; }
咱们发现,当遇到问题时不能直接上手去写,为何?由于咱们写的是代码,而不是bug,正确的程序是须要严谨的逻辑为前提,因此在写代码以前须要谨慎的思考各类临界的状况和异常,这是很是之重要的!
指针