在链式描述中,线性表元素的位置在内存中是随机的,每个元素都有一个明确的指针指向线性表的下一个元素的位置。

1.单向链表:
数据对象的每一个元素都用一个单元或者节点来描述,每个节点都明确包含另一个相关节点的位置信息。

线性表的链式描述图如下所示:

每个节点只有一个链,这种结构称为单向链表

重点: 链表的插入与删除

结构chainNode,数据成员element是节点的数据域,存储线性表的元素,数据成员next是节点的链域,存储下一个节点的指针。

定义链表类chain:

首先定义链表的节点的数据结构,结构体chainNode;

template<typename T>
struct chainNode    // 定义节点的数据结构
{// 数据成员T element;    // 数据域 chainNode<T>* next;     // 指针域//chainNode() {}chainNode(T& element)   // 结构体的构造函数 {this->element = element;} chainNode(T& element, chainNode<T>* next)   // 结构体的构造函数 {this->element = element;    // 这里的this的作用类似于类里面的this this->next = next;}
};

链表类chain的定义:

template<typename T>
class chain: public linearList<T>
{protected:bool checkIndex(int theIndex) const;   // 索引是否有效 chainNode<T>* firstNode;int listSize;public:chain(int init_capacity=10);chain(const chain<T>&);   // 拷贝构造函数~chain();    // 析构函数//抽象数据类型ADTbool empty() const;int size() const;T& get(int index);int indexOf(T& element) const;void erase(int index);void insert(int index);void output() const;
};

重点掌握的,链表的拷贝构造函数实现,析构函数实现,插入函数和删除函数

拷贝构造函数:

template<typename T>
chain<T>::chain(const chain<T>& new_chain)  // 重要
{listSize = new_chain.listSize;if(listSize==0)   // 要复制的链表为空 {firstNode = NULL;return;   // end}// 链表非空chainNode<T>* sourceNode = new_chain.firstNode;firstNode = new chainNode<T>(sourceNode->element);   // 结构体变量的初始化  chainNode结构体有两个构造方法,这是其中的一个 // firstNode = new chainNode<T>((*sourceNode).element) //解引用sourceNode = sourceNode->next;           // 原来链表的指针 chainNode<T>* targetNode = firstNode;   // 复制得到的链表的节点指针 while(sourceNode!=NULL){targetNode->next = new chainNode<T>(sourceNode->element);targetNode = targetNode->next;sourceNode = sourceNode->next;} targetNode->next = NULL;   // 链表结束
}

指针移动细节如下图所示:

析构函数:

析构函数逐个删除链表的节点,通过重复清除链表的首个元素节点,知道链表为空。在清除之前用变量保存第二个元素节点的指针。时间复杂度

template<typename T>
chain<T>::~chain()
{// 链表的析构函数, 删除链表的所有节点while(firstNode!=NULL){chainNode<T>* nextNode = firstNode->next;  // 保存链表第二个节点的指针 delete firstNode;     // 删除释放第一个节点的内存 firstNode = nextNode;    // 将第二个节点变为第一个节点 }
}

链表类chain的完整代码:
1. chain的基类,  抽象类linearList

#ifndef LINEAR_LIST_H
#define LINEAR_LIST_H #include <iostream>
using namespace std;template<typename T>    // 定义一个抽象类
class linearList
{public:// 抽象类中的纯虚函数 virtual ~linearList()  {};   // 析构函数virtual bool empty() const=0;virtual int size() const=0;virtual T& get(int index) const=0;virtual int indexOf(const T x) const=0;     // 这里定义的是虚函数,虚函数virtual functiuonName() const=0表示的是定义为纯虚函数,这个纯虚函数是只读函数 virtual void erase(int index) = 0;           // 这里定义的是虚函数,虚函数virtual functiuonName()=0表示的是定义为纯虚函数,这个纯虚函数不是只读函数virtual void insert(int index, T x) = 0;// virtual void output(ostream& out) const=0;
};#endif

2. 类chain的定义和实现:

#ifndef CHAIN_H
#define CHAIN_H
#include <iostream>#include "E:\back_up\code\c_plus_code\digui\external_file\linearlist.h"template<typename T>
struct chainNode    // 定义节点的数据结构
{// 数据成员T element;    // 数据域 chainNode<T>* next;     // 指针域//chainNode() {}chainNode(T& element)   // 结构体的构造函数 {this->element = element;} chainNode(T& element, chainNode<T>* next)   // 结构体的构造函数 {this->element = element;    // 这里的this的作用类似于类里面的this this->next = next;}
};template<typename T>
class chain: public linearList<T>
{protected://bool checkIndex(int theIndex) const;   // 索引是否有效 chainNode<T>* firstNode;int listSize;public:chain(int init_capacity=10);chain(const chain<T>& new_chain);   // 拷贝构造函数~chain();    // 析构函数//抽象数据类型ADTbool empty() const;int size() const;T& get(int index) const;int indexOf(T x) const;void erase(int index);void insert(int index, T x);void output() const;
};/*
template<typename T>
bool chain<T>::checkIndex(int index)
{return (index>=0&&index<=listSize)?true:false;
}
*/template<typename T>
chain<T>::chain(int init_capacity)   // 构造函数
{if(init_capacity<1)cout << "Init capacity should be greater than 0" << endl;firstNode = NULL;      // 链表初始化 listSize = 0;
}
#endiftemplate<typename T>
chain<T>::chain(const chain<T>& new_chain)  // 重要
{listSize = new_chain.listSize;if(listSize==0)   // 要复制的链表为空 {firstNode = NULL;return;   // end}// 链表非空chainNode<T>* sourceNode = new_chain.firstNode;firstNode = new chainNode<T>(sourceNode->element);   // 结构体变量的初始化  chainNode结构体有两个构造方法,这是其中的一个 // firstNode = new chainNode<T>((*sourceNode).element) //解引用sourceNode = sourceNode->next;           // 原来链表的指针 chainNode<T>* targetNode = firstNode;   // 复制得到的链表的节点指针 while(sourceNode!=NULL){targetNode->next = new chainNode<T>(sourceNode->element);targetNode = targetNode->next;sourceNode = sourceNode->next;} targetNode->next = NULL;   // 链表结束
}template<typename T>
chain<T>::~chain()
{// 链表的析构函数, 删除链表的所有节点while(firstNode!=NULL){chainNode<T>* nextNode = firstNode->next;  // 保存链表第二个节点的指针 delete firstNode;     // 删除释放第一个节点的内存 firstNode = nextNode;    // 将第二个节点变为第一个节点 }
}template<typename T>
bool chain<T>::empty() const
{return listSize==0;
} template<typename T>
int chain<T>::size() const
{return listSize;
}template<typename T>
T& chain<T>::get(int index) const
{/*if(checkIndex(index)){chainNode<T>* currentNode = firstNode;for(int i=0; i<index; i++){currentNode = currentNode->next;    //先找到index的前一个节点 }return currentNode->element; }else{cout << "The index is invalid" << endl;}*/chainNode<T>* currentNode = firstNode;for(int i=0; i<index; i++){currentNode = currentNode->next;    //先找到index的前一个节点 }return currentNode->element;
}template<typename T>
int chain<T>::indexOf(T the_element) const
{// 返回the_element首次出现的索引值// fouzefanhui -1chainNode<T>* currentNode = firstNode;int index_cnt = 0;while(currentNode!=NULL){if(currentNode->element == the_element){return index_cnt;}currentNode = currentNode->next;index_cnt ++;} return -1;
}template<typename T>
void chain<T>::insert(int index, T x)
{// 在链表中插入元素//chainNode<T>* currentNode = firstNode;// 插入元素得考虑是否在表头插入;if(index==0)   // 在表头插入 {firstNode = new chainNode<T>(x, firstNode);   // 造结构体构造方法 //firstNode->next = currentNode;} else           // 不是在表头插入 {chainNode<T>* currentNode = firstNode; for(int i=0; i<index-1; i++){currentNode = currentNode->next;}currentNode->next = new chainNode<T>(x, currentNode->next);   // 插入元素到链表index位置 }listSize++;
}template<typename T>
void chain<T>::erase(int index)
{// 1.检查index的合法性// 2.检查index==0if(index==0){chainNode<T>* currentNode = firstNode;firstNode = firstNode->next;delete currentNode;listSize--;} else{chainNode<T>* currentNode = firstNode;// int node_cnt = 0;for(int i=0; i<index-1; i++){currentNode = currentNode->next;}// currentNode 指向第index-1个节点chainNode<T>* tmp = currentNode->next;    // tmp指向第index个节点currentNode->next = tmp->next;delete tmp; listSize--;}}template<typename T>
void chain<T>::output() const
{chainNode<T>* currentNode = firstNode;int node_cnt = 0;while(currentNode!=NULL)   //遍历链表的所有元素{cout << currentNode->element << " ";if((node_cnt+1)%10==0){cout << endl;}currentNode = currentNode->next;node_cnt++;}
}

3。测试函数:
main.cpp

#include <iostream>
#include <string>
#include <time.h>
#include "E:\back_up\code\c_plus_code\digui\external_file\linearlist.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\arraylist.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\chain.h"using namespace std;// 实现友元函数int main(int argc, char *argv[])
{/*arrayList<double> array(3);for(int i=0; i<10; i++){array.insert(i, i);}//array.insert(0, a);//array.insert(1, b);array.output();array.insert(9, 9.9);array.output();*/chain<int> chain_1;for(int i=0; i<10; i++){chain_1.insert(i, i*i);}cout << "The size of chain is " << chain_1.size() << endl;chain_1.output();// cout << "The size of chain is " << chain_1.get() << endl;chain_1.insert(3, 520);cout << "The size of chain is " << chain_1.size() << endl;chain_1.output();chain_1.erase(9);cout << "The size of chain is " << chain_1.size() << endl;chain_1.output();cout << "The " << 3 << " element in chain is " << chain_1.get(3) << endl;return 0;
}

测试结果:

------------------------------------------------------------------------------------------------

给类chain添加clea()功能:

template<typename T>
void chain<T>::clear()
{while(firstNode!=NULL){chainNode<T>* nextNode = firstNode->next;delete firstNode;firstNode = nextNode;}listSize = 0;
}

main.cpp

#include <iostream>
#include <string>
#include <time.h>
#include "E:\back_up\code\c_plus_code\digui\external_file\linearlist.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\arraylist.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\chain.h"using namespace std;// 实现友元函数int main(int argc, char *argv[])
{/*arrayList<double> array(3);for(int i=0; i<10; i++){array.insert(i, i);}//array.insert(0, a);//array.insert(1, b);array.output();array.insert(9, 9.9);array.output();*/chain<int> chain_1;for(int i=0; i<10; i++){chain_1.insert(i, i*i);}cout << "The size of chain is " << chain_1.size() << endl;chain_1.output();chain_1.clear();if(chain_1.empty()){cout << "The chain is empty" << endl;}else{cout << "The chain is not empty" << endl;}return 0;
}

测试结果:

性能比较:

1.内存比较:

在数组描述的线性表中,数组满的时候,数组的长度需要加倍,,当线性表的元素个数不及数组长度的1/4时,数组元素减半。

n个元素的线性表可以存储在n~4n长度的数组中。 假设每个元素需要s个字节,则所占的空间为ns~4ns.对于链表,n个元素分配n个节点,每个指针4字节大小,则所占的空间的小为n(s+4),因此在选择线性表的描述方法时,空间上的差异不是决定因素。

2.时间比较

例如get(int index)操作,链表的时间复杂度是   ,数组的时间复杂度是  ,其他操作的时间如下:

--------------------------------------------------f分割线--------------------------------------------------------

给链表添加一些新的方法

1.实现 setSize()方法:

数据结构与算法笔记(三) 线性表(链式描述) 链表相关推荐

  1. 数据结构与算法笔记(二) 线性表(数组描述)

    c++常用的数据描述方法是数组描述和链式描述,线性表可以用来说明这两方法,先介绍数组描述的线性表.后面再介绍链式描述的线性表. C++ STL容器vector和list相当于线性表的数组描述和链式描述 ...

  2. 【数据结构和算法笔记】线性表的查找(平均查找长度,二分法,判定树)

    查找: 给定一个值k,在含有n个元素的表中找出关键字等于k的元素,若找到,则查找成功,否则,查找失败 查找前首先确定(1)存放数据的数据结构是什么(2)元素是否有序 动态查找表:查找的同时做修改操作( ...

  3. 【数据结构与算法】之线性表的应用和操作

    数据结构概念 数据结构:是相互之间存在一种或多种特定关系的数据元素的集合. 数据结构的逻辑结构:数据对象中数据元素之间的相互关系,分为线性结构.树形结构.图形结构以及集合结构. 数据结构的物理结构:数 ...

  4. 数据结构与算法2:线性表的顺序存储与链式存储

    文章目录 线性表 定义 线性表的抽象数据类型(Abstract Data Type) 线性表的顺序存储结构 线性表的链式存储结构 单链表(single linked list) 静态链表 (stati ...

  5. 2012-2-24 《数据结构》读书笔记2 线性表

    "软件只不过是人的思想产物,软件可能是人能造出来的最复杂的实体"这是昨天晚上UML(统一建模语言)老师的一句话,也更加坚定了我学习软件的决心,真的有这么复杂么,其实还是自己不够用心 ...

  6. 数据结构与算法第二章 线性表、栈、队列、数组、字符串、树、二叉树、哈希表的增删查

    03 增删查:掌握数据处理的基本操作,以不变应万变 通过前面课时的学习,相信你已经建立了利用数据结构去完成时空转移的思想.接下来,你需要在理论思想的指导下灵活使用.其实,要想灵活使用数据结构,你需要先 ...

  7. 【数据结构与算法基础】线性表

    写在前面 挺早之前看的数据结构和算法了,但是最近刷LeetCode上题目的时候发现还不是很熟练(都忘光了....),于是狠心再来一遍.边整理边刷题,用的教材是北大裘宗燕的<数据结构与算法pyth ...

  8. 数据结构之线性表-链式存储之单链表(一)

    本人文笔较差,语文从来不及格,基础不好,写此类文章仅供自己学习,理解队列及其他知识,高手大神请略过.参考书籍 <数据结构与算法分析-Java语言描述> 1.1 单链表简介 线性表的最大的缺 ...

  9. 数据结构与算法:06 线性表

    06 线性表 知识结构: 1. 线性表的定义与操作 1.1 线性表的定义 线性表(Linear List)是由n(n≥0)n (n≥0)n(n≥0)个相同类型的数据元素a0,a1,⋯,an−1a_0, ...

  10. 【数据结构与算法】删除线性表中的零元素

    题目 删除顺序结构线性表中的零元素,不改变原表的顺序. input: 10,2,0,0,5,7,0,4,0,0 output: 10,2,5,7,4 解决 解法一 发现一个零元素,就删除一个.将后面的 ...

最新文章

  1. BZOJ1597: [Usaco2008 Mar]土地购买(dp 斜率优化)
  2. 零基础参加java培训哪家机构好
  3. 在Eclipse中配置Tomcat服务
  4. MySQL Group Replication 介绍
  5. js/jquery判断浏览器的方法总结
  6. Windows平台下Makefile学习笔记
  7. C++:类模板与模板类
  8. 浅谈web网站架构演变过程
  9. linux怎么看java环境变量_linux下配置jdk环境变量以及查看java版本
  10. windows smb更改端口_SMB协议(使用说明+过程详解+抓包分析)
  11. 不了解沙特,那你就看不懂硅谷
  12. [NPOI2.0] 使用NPOI读取和导出Excel文件
  13. 一题多解 —— 二项式分布的期望和方差的计算
  14. SAM4E单片机之旅——11、UART之PDC收发
  15. 微信小程序——实现时钟样式
  16. python做var模型的滞后阶数怎么确定_请问关于VAR模型的滞后阶数怎么确定?
  17. mysql5.1不支持中文,MySQL_MySQL5.1的中文支持的一个改进, MySQL 5.1的中文支持的一个改 - phpStudy...
  18. 有逆时针将视频画面旋转90度的方法吗?
  19. 浙江大学计算机学院钱沄涛实验室,浙江大学导师介绍--钱沄涛
  20. 年货来咯:精选年度最受欢迎干货,覆盖客户端、服务端、前端、数据、算法……...

热门文章

  1. SpringCloud工作笔记069---The Hystrix timeout of 60000ms for the command sc-auth is set lower than the
  2. 数据库工作笔记003---在Centos中导入sql文件的方法
  3. JAVA面试要点007---equals和==的区别小结
  4. java分布式(java反汇编)
  5. 计算机课程表教案,计算机专业课程表
  6. python开发每月工资_做python开发想要月薪20K不会这些怎么行?
  7. 接口里面能有构造器吗?_家用弱电箱里空空如也,装修时应该怎么在里面接线呢?能拆掉吗?...
  8. js获取今天剩余时间_js动画,setTimeout/setInterval的不准确
  9. arch linux arm下载_linux系统下编译给android JNI调用的Gmssl库
  10. 简单的java程序代码带注释,Java:基于注释的代码注入的简单技术?