您的位置:首页 > 编程语言 > C语言/C++

【C++】 双向链表.cpp

2016-03-05 16:54 351 查看
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

一般我们都构造双向循环链表,因为双向链表解决了单向链表的不足和问题,而单链表因为出现的问题多,所以在面试中经常会考到单链表的问题。

在这里,我用 .cpp对双向链表的基本操作进行实现。

具体代码如下:
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 文件:(测试)
#include<iostream>
#include<assert.h>
using namespace std;

#include "DoubleSList.h"  //双向链表

int main()
{
Test();
return 0;
}
我们发现,当遇到问题时不能直接上手去写,为什么?因为我们写的是代码,而不是bug,正确的程序是需要严谨的逻辑为前提,所以在写代码之前需要谨慎的思考各种临界的情况和异常,这是非常之重要的!

本文出自 “Vs吕小布” 博客,谢绝转载!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: