//////////////////////////////////////////////////////////////////////////////////////
/////// 这里建立两个类,一个节点类和一个List类,与单链表不同的是双向链表的节点要多一
////// 个前驱指针,相应的,双向链表函数实现要与单链表实现有所差异 typedef int DataType; //struct LinkNode //节点类(复合形态)
//{
// friend class SList;
//将SList设为友元,便于SList类可以访问节点类的私有成员
//public:
// LinkNode(const DataType x);
//private:
// DataType _data; //节点的数据
// LinkNode* _next; //指向该节点的下一个节点
// LinkNode* _prev; //指向该节点的前一个节点
//}; //直接用struct定义LinkNode类,因为struct的成员默认为公有数据成员,所以可直接访问
struct LinkNode //节点类(建议写法)
{
LinkNode(const DataType x);
DataType _data; //节点的数据
LinkNode* _next; //后继指针
LinkNode* _prev; //前驱指针
}; class List //链表类
{
public:
List(); //构造函数
List(const List& s); //拷贝构造
List &operator=(List& s); //赋值运算符的重载
~List(); public:
void Reverse();
void Swap(List& s);
void PrintSList(); //打印链表
void PushBack(const DataType& x); //在尾部插入一个节点
void Clear(); //链表置空
void PopBack();
void PushFront(DataType x); //头插
void PopFront(); //删除首节点
void Insert(LinkNode* pos, DataType x);//固定位置插入一个节点
void Erase(LinkNode* pos); //删除某一节点
LinkNode* Find(DataType x); //查找节点并返回这个节点的地址
int Amount(); //计算链表节点的数目
void Remove(DataType x); //查找某节点并删除 private:
LinkNode* _head; //指向头结点
LinkNode* _tail; //指向尾节点
};

List.h

   #include<iostream>
using namespace std;
#include<assert.h>
#include"List.h" //节点类构造函数*
LinkNode::LinkNode(const DataType x)
:_data(x)
, _next(NULL)
, _prev(NULL)
{} //链表类*
List::List() //构造函数
: _head(NULL)
, _tail(NULL)
{} List::List(const List& s) //拷贝构造
: _head(NULL)
, _tail(NULL)
{
if (s._head == NULL)
{
return;
}
LinkNode* tmp = s._head;
while (tmp)
{
PushBack(tmp->_data);
tmp = tmp->_next;
} } //赋值运算符的重载(传统方法)
//SList & SList::operator=(const SList& s)
//{
// if (this != &s)
// {
// _head = NULL;
// _tail = NULL;
// LinkNode* tmp = s._head;
// do{
// PushBack(tmp->_data);
// tmp = tmp->_next;
// } while (tmp != s._head);
// }
// return *this;
//} //赋值运算符的重载(高效写法)*
/*void SList::Swap(SList& s)
{
swap(_head, s._head);
swap(_tail, s._tail); }
SList& SList::operator=(SList &s)
{
if (this != &s)
{
SList tmp(s);
Swap(tmp);
}
return *this;
}*/ List& List::operator=(List &s) //赋值运算符的重载再优化(推荐写法)
{
if (this != &s)
{
swap(_head, s._head);
swap(_tail, s._tail);
}
return *this;
}
List::~List() //析构
{
Clear();
} void List::Reverse() //链表逆置(利用头插新节点的方法)
{
if (_head == NULL || _head== _tail)
{
return;
}
int ret = Amount(); /* // 方法一(相当于用头插的方式重新建立链表)
_tail = new LinkNode(_head->_data);
LinkNode* begin = NULL;
LinkNode* tmp = _tail;
while (--ret)
{
LinkNode* del = _head;
_head = _head->_next;
delete del;
begin = new LinkNode(_head->_data);
begin->_next = tmp;
tmp->_prev = begin;
tmp = begin;
}
_head = begin;*/ ////// 方法二(只是交换对称位置节点的数据)**(高效)
LinkNode* begin = _head;
LinkNode* end = _tail;
while (ret)
{
if (end->_next == begin)
break;
ret /= ;
swap(begin->_data, end->_data);
begin = begin->_next;
end = end->_prev;
} /*// 方法三 交换前驱和后继指针
swap(_head, _tail);
LinkNode* cur = _head;
while (cur)
{
swap(cur->_prev,cur->_next);
cur = cur->_next;
}
*/ } //打印链表*
void List::PrintSList()
{
//头结点为空时,无需打印链表
if (_head == NULL)
{
cout << "This SList is Empty !" << endl;
return;
}
else
{
LinkNode* tmp = _head;
while (tmp)
{
cout << tmp->_data << "-->";
tmp = tmp->_next;
}
cout <<"NULL"<< endl;
}
} void List::PushBack(const DataType& x) //在尾部插入一个节点*
{
//如果链表为空,插入节点后只有一个节点,此时_head=_tail
if (_head == NULL)
{
_head = new LinkNode(x);
_tail = _head;
}
else
{
_tail->_next = new LinkNode(x);
_tail->_next->_prev=_tail;
_tail = _tail->_next;
}
} void List::Clear() //链表置空*
{
LinkNode* begin = _head;
while (begin != _tail)
{
_head = _head->_next;
delete begin;
begin = _head;
}
_head = NULL;
_tail = NULL;
} void List::PopBack() //尾删
{
if (_head == NULL)
{
cout << "This SList is empty !" << endl;
}
else if (_head == _tail)
{
delete _head;
_head = NULL;
_tail = NULL;
}
else
{
LinkNode* cur = _head;
while (cur->_next != _tail)
{
cur = cur->_next;
}
delete _tail;
_tail = cur;
_tail->_prev = cur->_prev;
_tail->_next = NULL;
}
} void List::PushFront(DataType x) //头插*
{
if (_head == NULL)
{
PushBack(x);
}
else
{
LinkNode* tmp = _head;
_head = new LinkNode(x);
_head->_next = tmp;
tmp->_prev = _head;
}
} void List::PopFront() //删除首节点
{
if (_head == NULL)
{
cout << "This SList is empty !" << endl;
return;
}
LinkNode* tmp = _head;
_head = _head->_next;
_head->_prev = NULL;
delete tmp;
} //固定位置插入一个节点(这个函数需和Find函数搭配使用)
//先用Find函数找到新节点需要插入的位置
//(将Find函数的返回值传给Insert函数的参数pos),再在pos节点后面插入新节点x
void List::Insert(LinkNode* pos, DataType x) //*
{
assert(pos);
if (pos == _tail)
{
PushBack(x);
}
else
{
LinkNode* tmp = new LinkNode(x);
tmp->_next = pos->_next;
pos->_next = tmp;
tmp->_next->_prev = tmp;
tmp->_prev = pos;
}
} //删除某一节点,同样,要先找到该节点并传参给Erase函数
void List::Erase(LinkNode* pos)
{
assert(pos);
if (pos == _tail)
{
PopBack();
}
else if (pos == _head)
{
PopFront();
}
else
{
pos->_prev->_next = pos->_next;
pos->_next->_prev = pos->_prev;
delete pos;
}
} //查找节点并返回这个节点的地址
LinkNode* List::Find(DataType x)
{
if (_head == NULL)
{
cout << "This SList is empty !" << endl;
return NULL;
}
else
{
LinkNode* tmp = _head;
while (tmp != NULL)
{
if (tmp->_data == x)
{
return tmp;
}
tmp = tmp->_next;
}
return NULL;
}
} int List::Amount() //计算链表节点的数目
{
if (_head == NULL)
{
return ;
}
else
{
int count = ;
LinkNode* cur = _head;
while (cur != _tail)
{
count++;
cur = cur->_next;
}
return ++count;
}
} void List::Remove(DataType x) //查找某节点并删除
{
if (_head == NULL)
{
cout << "This SList is empty !" << endl;
}
else
{
LinkNode* tmp = Find(x);
if (tmp != NULL)
{
Erase(tmp);
}
}
}

List.cpp

 #include"List.h"
#include<stdlib.h>
#include<iostream>
using namespace std; void Test1()
{
List list1;
list1.PushBack();
list1.PushBack();
list1.PushBack();
list1.PushBack();
list1.PushBack();
list1.PushBack();
list1.PrintSList(); /* List list2(list1);
list2.PrintSList();*/ List list2=list1;
list2.PrintSList();
//list2.PopBack();
//list2.Clear();
//list2.PushFront(0);
//list2.PopFront(); //////检验Find函数
////LinkNode* ret=list2.Find(4);
////if (ret != NULL)
////{
//// cout << "ret:" << ret << " " << ret->_data << endl;
////}
////else
////{
//// cout << "Not exit !" << endl;
////} /* int ret=list2.Amount();
cout << ret << endl;*/ //list2.Erase(list2.Find(5));
//list2.Insert(list2.Find(2), 0);
//list2.Remove(3);
list2.Reverse();
list2.PrintSList();
} int main()
{
Test1();
system("pause");
}

Test.cpp

双向链表(C++实现)的更多相关文章

  1. 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...

  2. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  3. 剑指Offer面试题:25.二叉搜索树与双向链表

    一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...

  4. Linux 内核数据结构:Linux 双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  5. Linux 内核数据结构:双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  6. 线性表-双向链表(LinkedList)

    双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>. LinkedList源码 0.首先这个类中的两个变量 private transient Entry ...

  7. Shuffling Machine和双向链表

    1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/t ...

  8. MS - 1 - 把二元查找树转变成排序的双向链表

    ## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10       ...

  9. javascript中的链表结构—双向链表

    1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...

  10. Java自己实现双向链表LinkList

    /** * <p> * Node 双向链表实体类 * <p> * * @author <a href="mailto:yangkj@corp.21cn.com& ...

随机推荐

  1. UIViewController新方法的使用(transitionFromViewController:toViewController:duration:options:animations:completion:)

    iOS5中,UIViewController新添加了几个方法: - (void)addChildViewController:(UIViewController *)childController N ...

  2. 为什么返回的数据前面有callback? ashx/json.ashx?的后面加 callback=? 起什么作用 js url?callback=xxx xxx的介绍 ajax 跨域请求时url参数添加callback=?会实现跨域问题

    为什么返回的数据前面有callback?   这是一个同学出现的问题,问到了我. 应该是这样的: 但问题是这样的: 我看了所请求的格式和后台要求的也是相同的.而且我也是这种做法,为什么他的就不行呢? ...

  3. Java后台代码调用Spring的@Service Bean的方式

    比如:在我的project中有一个类CompassIndexOperation,以: @Service("CompassIndexOperation") @Transactiona ...

  4. Spring事务管理之编程式事务管理

    © 版权声明:本文为博主原创文章,转载请注明出处 案例:利用Spring的编程式事务管理模拟转账过程 数据库准备 -- 创建表 CREATE TABLE `account`( `id` INT NOT ...

  5. 解决Linux上解压jdk报错gzip: stdin: not in gzip format

    最近在阿里上买了个服务器玩,需要安装jdk,在解压过程中遇到了一些问题,又是一番Google度娘,终于解决了.问题原因让我有点无奈…… 输入 #tar -xvf jdk-8u131-linux-x64 ...

  6. android开发游记:meterial design 5.0 开源控件整套合集 及使用demo

    android 的5.0公布不光google官方给出了一些新控件,同一时候还给出了一套符合material design风格的设计标准,这套标准将未来将覆盖google全部产品包括pc端,站点,移动端 ...

  7. Cassandra安装和初次使用

    Cassandra安装和初次使用 卡珊德拉(Cassandra)又译卡桑德拉.卡珊卓,为希腊.罗马神话中特洛伊(Troy)的公主,阿波罗(Apollo)的祭司.因神蛇以舌为她洗耳或阿波罗的赐予而有预言 ...

  8. 【JMeter4.0学习(十)】之JMeter函数简单运用以及结合正则表达式提取器

    下面来简单的举个栗子: 首先,把函数和正则表达式提取器放在一块来介绍,如下所示: 1.结构完整展示,下面再一步一步创建添加: 2.添加线程组: 3.首先添加HTTP请求1 4.添加结果树后,运行后查看 ...

  9. np_utils.to_categorical

    https://blog.csdn.net/zlrai5895/article/details/79560353 多类分类问题本质上可以分解为多个二分类问题,而解决二分类问题的方法有很多.这里我们利用 ...

  10. C#通过代码彻底结束桌面进程explorer,解决自动重启问题

    C# 通过代码 Process.Kill 方法杀死桌面进程后,会自动重启 其实可以通过 Taskkill 指令结束桌面进程, 在命令行查看 taskkill 帮助, TASKKILL [/S syst ...