【Weiss】【第03章】双链表例程
双链表因为多了个前向指针,需要考虑的特殊因素多了一倍
所以中间插入(这儿没写)和中间删除会比较复杂。
其它倒没什么特别的,代码如下。
测试代码
#include <iostream>
#include "double_linklist.h"
using namespace std;
using namespace doublelinklist;
template class DList<int>;
int main(void)
{
DList<int> number; //测试插入
cout << "/*additem()*/" << endl;
number.additem();
number.additem();
number.additem();
number.additem();
number.additem();
number.additem();
number.additem();
number.traverse();
cout << "\n" << flush;
number.reverse();
cout << "\n/*end*/\n\n" << flush; //测试获取长度
cout << "/*length()*/" << endl;
cout << number.size() << endl;
cout << "/*end*/\n\n" << flush; //测试获得头元素
cout << "/*getfirst()*/" << endl;
cout << number.getfirst() << endl;
cout << "/*end*/\n\n" << flush; //测试删除存在的元素(头尾及中间元素各一)
cout << "/*remove()*/" << endl;
number.remove();
number.remove();
number.remove();
number.traverse();
cout << "\n" << flush;;
number.reverse();
cout << "\n/*end*/\n\n" << flush; //测试删除不存在的元素
cout << "/*remove()*/" << endl;
number.remove();
cout << "/*end*/\n\n" << flush; //测试清空,并测试从空表中删除元素
cout << "/*clear(),remove()*/" << endl;
number.clear();
number.remove();
cout << "/*end*/\n\n" << flush; system("pause");
} double_linklist_driver
实现代码
#ifndef DOUBLELINKLIST
#define DOUBLELINKLIST
#include <iostream> using namespace std; namespace doublelinklist
{ //链表节点模板
template <typename T> struct Node
{
Node<T>() : next(nullptr),prev(nullptr){}
Node<T>(const T &item, Node<T>* ptrn = nullptr, Node<T>* ptrp = nullptr) : data(item), next(ptrn), prev(ptrp){}
T data;
Node<T>* next;
Node<T>* prev;
};
//头节点及链表主体操作
template <typename T> class DList
{
//构造函数
public:
DList<T>() : length(), front(nullptr){}
//接口
public:
//返回长度
unsigned int size()const{ return length; }
//返回头指针
Node<T>* begin()const{ return front; }
//判断是否为空
bool empty()const{ return length == ; }
//获得头元素
T getfirst()const{ return front->data; }
//获得尾元素
T getlast()const{ return rear->data; }
//#查找元素所在地址
Node<T>* find(const T &item)const;
//#尾部加入新元素
bool additem(const T &item);
//#删除指定元素
bool remove(const T &item);
//#遍历顺序输出链表元素
void traverse()const;
//#遍历倒序输出链表元素
void reverse()const;
//清空链表
void clear(); //辅助函数
private:
//#查找元素前驱
Node<T>* find_prev(const T& item)const;
//数据
private:
unsigned int length;
Node<T>* front;
Node<T>* rear;
}; //如果元素为头元素或元素不存在则返回nullptr,否则返回前驱
template <typename T> Node<T>* DList<T>::find_prev(const T& item)const
{
if (length == )
return nullptr;
if (front->data == item)
return nullptr;
for (Node<T>* iter = front; iter->next != nullptr; iter = iter->next)
{
if (iter->next->data == item)
return iter;
}
return nullptr;
}
//调用find_prev,如果元素存在则返回地址,不存在则返回nullptr
template <typename T> Node<T>* DList<T>::find(const T &item)const
{
Node<T>* iter = find_prev(item);
if (length == )
return nullptr;
if (front->data == item)
return front;
return iter->next;
}
template <typename T> bool DList<T>::additem(const T &item)
{
Node<T>* pnew = new Node<T>(item);
//原链表无元素
//头尾指针均指向新节点,且新节点前后指针默认为nullptr
if (length == )
front = rear = pnew;
else
{
rear->next = pnew;
pnew->prev = rear;
rear = pnew;
}
++length;
return true;
}
//删除操作相对复杂
template <typename T> bool DList<T>::remove(const T &item)
{
//先判断链表是否空避免front->data未定义
if (length == )
{
cout << "No data!" << endl;
return false;
}
Node<T>* iter = find_prev(item);
//find_prev返回nullptr,且首元素不等,说明链表中无此元素
if (iter == nullptr && front->data != item)
{
cout << "Can not find!" << endl;
return false;
}
Node<T>* save;
//如果元素是首元素
//则仅需将save后继(如果存在)的前向指针改为nullptr
//如果save无后继,说明链表删除后为空,将rear置空
if (front->data == item)
{
save = front;
front = front->next;
if (save != rear)
save->next->prev = nullptr;
else
rear = nullptr;
}
//如果元素不是首元素
//则save的前驱iter的后向指针需改指向save后继
//同时,save后继(如果存在)的前向指针改为指向save的前驱iter
//如果save无后继,则rear要指向新的尾节点
else
{
save = iter->next;
iter->next = save->next;
if (save != rear)
save->next->prev = iter;
else
rear = iter;
}
delete save;
--length;
return true;
}
template <typename T> void DList<T>::traverse()const
{
if (length != )
{
for (Node<T>* iter = front; iter != nullptr; iter = iter->next)
cout << iter->data << ends;
}
}
template <typename T> void DList<T>::reverse()const
{
if (length != )
{
for (Node<T>* iter = rear; iter != nullptr; iter = iter->prev)
cout << iter->data << ends;
}
}
template <typename T> void DList<T>::clear()
{
Node<T>* iter;
while (front != nullptr)
{
iter = front;
front = front->next;
delete iter;
}
front = rear = nullptr;
length = ;
}
}
#endif
【Weiss】【第03章】双链表例程的更多相关文章
- 【Weiss】【第03章】链表例程的一些修改
主要是,感觉原来的链表例程通过Node的分配形成了链表,但是没有自动消除Node的办法比较危险,一旦在clear()之前把链表赋了其它值就内存泄漏了. 所以改了析构函数,自动清理分配出来的内存.既然改 ...
- 【Weiss】【第03章】链表例程
这种基础例程,如之前所提,会有一个实现和一个简单的测试代码. 链表其实没什么可说的,其实包括后面的栈和队列也没什么可说的,直接放代码吧. 下面这个是测试代码 #include <iostream ...
- 【Weiss】【第03章】队列例程
前几个例程还是相当简单的,把链表即时改了一下就是队列了. 还有想了一下,决定这种例程的代码放法是:先把测试代码默认折叠放在前面,然后把实现代码默认展开放在后面. 测试代码如下: #include &l ...
- 【Weiss】【第03章】栈例程
写栈比队列更简单一些,毕竟只有一个数据出入口. 之前用C在程序里模拟栈代替递归的时候,直接搞个数组来实现都是非常轻松愉快的事情. 不多说,放代码. 测试代码 #include <iostream ...
- 【Weiss】【第03章】练习3.3:通过交换指针交换单/双链表元素
[练习3.3] 通过之调整指针(而不是数据)来交换两个相邻的元素,使用 a.单链表 b.双链表 Answer: 先放测试代码,折叠标题可以看到分别是哪种链表的测试. 实测可满足题意,但单链表和双链表的 ...
- C和指针 第十二章 使用结构和指针 双链表和语句提炼
双链表中每个节点包含指向当前和之后节点的指针,插入节点到双链表中需要考虑四种情况: 1.插入到链表头部 2.插入到链表尾部 3.插入到空链表中 4.插入到链表内部 #include <stdio ...
- 《程序员代码面试指南》第二章 链表问题 在单链表和双链表中删除倒数第K个节点
题目 在单链表和双链表中删除倒数第K个节点 java代码 /** * @Description:在单链表和双链表中删除倒数第K个节点 * @Author: lizhouwei * @CreateDat ...
- 【Weiss】【第03章】练习3.6:有序多项式相加
[练习3.6] 编写将两个多项式相加的函数.不要毁坏输入数据.用一个链表实现. 如果这两个多项式分别有M项和N项,那么你程序的时间复杂度是多少? 两个按幂次升序的多项式链表,分别维护一个指针. 幂较小 ...
- 【Weiss】【第03章】练习3.2
[练习3.2] 给你一个链表L和另一个链表P,它们包含以升序排列的整数.操作printlots(L,P)将打印L中那些由P所指定的位置上的元素. 例如,如果p=1,3,4,6,那么,L的第一.第三.第 ...
随机推荐
- 2015-09-14-初级vector
标准库vector类型 #include<vector> using std::vector; vector为一个类模板. vector的初始化 vector<T> v1; v ...
- Sublime Text2 使用心得总结
sublime text2是开发代码编辑的神器 ,编辑器界面优美,操作速度快速.而且Sublime Text2是一款跨平台的编辑器,再也不用为换平台而找不到合适的.熟悉的编辑器担忧了. Sublime ...
- Nginx笔记总结六:Nginx location配置
语法规则:location [= | ~ | ~* | ^~] /uri/ {....} = 表示精确匹配 ^~ 表示uri以某个常规字符串开头 ~ 表示区分大小写的正则表达式 ~* 表示不区分大小写 ...
- java文件压缩ZipOutPutStream
其实最好的书籍就是javaAPI 1.创建ZipOutPutStream流,利用BufferedOutputStream提个速. 2.新建zip方法,用来压缩文件,传参 3.zip方法利用putNex ...
- Microsoft Translator发布粤语文本翻译
今天,Microsoft Translator发布了粤语的文本翻译,新的语言增加将继续丰富微软翻译产品的生态系统*,让更多组织和个人能够快速且高效地实现翻译应用.在中国,大有约5500万人使用粤语(语 ...
- IDEA 运行junit单元测试方法
配置Run,增加Junit 最终配置如下:
- 基于layPage分页插件浅析两种分页方式
最近在开发过程中经常用到分页,今天挤出些时间来捋一捋自己的经验 在web开发中,一般显示数据列表页时,我们会用到分页控件来显示数据.采用分页一般基于两种不同的需求,一种是数据量不算很大,但是在页面展示 ...
- 达拉草201771010105《面向对象程序设计(java)》第三周学习总结
达拉草201771010105«面向对象程序设计(java)»第三周学习总结 第一部分:实验部分 1.实验目的与要求 (1)进一步掌握Eclipse集成开发环境下java程序开发基本步骤: (2)熟 ...
- OpenCV读一张图片并显示
Java 版本: JavaCV 用OpenCV读一张图片并显示.只需将程序运行时的截图回复.如何安装配置创建项目编写OpenCV代码,可参考何东健课件和源代码或其他资源. package com.gi ...
- win10下LoadRunner12 下载安装图文教程
1.下载安装包: 链接:https://pan.baidu.com/s/1hiGC9FjfKOFRWHVfMAHaeg 提取码:sr8x 如下图所示,咱们直接安装社区版“HP_LoadRunner_1 ...