前言

前一篇文章我们了解了什么是数据结构以及为什么要学习数据结构。还记得选择数据结构的原则吗?那就是“因地制宜,适合的就是最好的”。今天我们就将正式敲开数据结构的大门。和上一篇文章一样,我们以一句诗作为引子来引出今天的主题,这句诗就是“千里姻缘一线牵”。其中的“线”就是我们今天的主题,说到线我们可能会想到故事发展的时间线,时间就有先后顺序,而且顺序很重要,比如说有时候你会听到这样一句话“并不是你不够优秀,而是她先遇到了他“。也许这个时候你就能体会到顺序的重要。在数据结构中也有一种数据结构非常讲究出场的顺序,那就是线性表。线性表可以说是数据结构世界里的绝世好男人,它不仅讲究顺序,而且还永远都不会出轨。他的感情经历如图所示就像一条线一样,从头到尾不会分叉。

如同现实社会一样,有暖男就会有渣男,数据结构里的的渣男叫做二叉树,不是劈腿就是在劈腿的路上,不过这又是另一段精彩的故事。不过今天还是专注于专一的线性表。

线性表的表示

我们前面说到线形表的两个特性,一个是讲究顺序,一个是专一不分叉。这是线性表的逻辑结构,逻辑都是抽象的,所以我们可以把逻辑结构看成一个类,两个特性就是类的属性。真正把线形表存储到计算机的结构我们称之为存储结构,我们可以把存储结构看成类的实例,一个类可以有多个不同的实例。我们今天就了解一下最常见的两种线形表的实例顺序表和单链表。

顺序表

想象这样一个场景,一天晚上闲来无事睡不着,你就开始和你下铺的室友开始吹牛b,互相吹嘘自己的情史,说第一任女朋友是刘亦菲,第二任女朋友是杨幂,第三任女友刘诗诗,第四任女朋友是欧阳娜娜。也许你自己都没发现,说着说着,你就发现你的脑子里出现了这样一张表。

后来你总感觉有点不对劲,直到看到你和女朋友屏保,才发现原来把现女友忘了,赶紧把现女友加上,表就变成了这样。

后来你想想,你和杨幂也就暧昧了几天,应该不算你女朋友,她在这张表不配拥有姓名,所以你决定把她删了。这是你发现一个问题,虽然你只是删除了杨幂,可杨幂之后的人序号都要改变,她之后的人都受到了影响。

看着这张表,忽然你的脑海里晃过一个熟悉的身影,那是一个穿着校服扎着马尾的女孩,是她让你知道了喜欢一个人是什么样的感觉,所以你毫不犹豫的加上了她的名字。从回忆中醒来,你发现了和删除同样的问题,当你加入一个人的时候,她后面的人都会受到影响。

实现

当我们将其用代码实现结果如下,这里采用的是java语言,其他语言实现方式略有不同,但是思想是一样的。

public class SequenceList<T> {private final int maxSize = 10;private T[] listArray;private int length;// 创建顺序表public SequenceList() {this.length = 0;this.listArray = (T[]) new Object[maxSize];}// 创建顺序表public SequenceList(int n) {if(n < 0 || n > maxSize) {System.out.println("Error");System.exit(1);} else {this.length = 0;this.listArray = (T[]) new Object[n];}}//表背增加表项public void add(T object) {listArray[length] = object;length++;}//插入表项public boolean insert(T object, int position) {if(position < 0 || position > length + 1) {System.out.println("error");return false;} else if(length == listArray.length) {T[] p = (T[]) new Object[length * 2];for(int i = 0; i < length + 1; i++) {p[i] = listArray[i];}listArray = p;}for (int i = length + 1 ; position < i; i--) {listArray[i - 1] = listArray[i];i--;}listArray[position] = object;return true;}//移除表项public boolean remove( int position) {if(isEmpty()||position < 0 || position > length) {System.out.println("error");return false;}for ( int i = position; i < length + 1; i++) {listArray[i] = listArray[i + 1];}return true;}//判断顺序表是否为空public boolean isEmpty() {return length == 0;}//清空顺序表public void  clear() {length = 0;}//更新表项public boolean update(T object, int position) {if(isEmpty() || position < 0 || position > length) {System.out.println("error");return false;}listArray[position] = object;return true;}//遍历表项public void nextOrder() {for(int i = 0; i < length; i++) {System.out.println(listArray[i]);}}
}

单链表

当你在思考问题的时候,你室友这一边也陷入了深深的回忆,那是2012年的第一场雪,来的没有比以往时候更晚一些,那是一个穿着鹅黄色羽绒服留着齐刘海的女孩,她的名字叫做娜扎(此处略去一万字),娜扎之后是热巴(此处略去两万字),热巴之后又遇到了。。。(此处略去十万字)。

我们注意到顺序表的实现是在数组的基础上做了一些改造,而单链表是建立在节点的基础上,节点的结构如下,其中数据域中存储数据,在我们的例子中就是“娜扎”等等,指针是指向下一个节点,例如我们例子中的“娜扎之后”等等。

你室友的经历随着一声叹息连成了一张链表如下图所示。

当你的室友想删去娜扎时,结果图就变成了这样,我们注意到,虽然删去了娜扎,但是好像娜扎后面的节点并没有受到影响。

当增加一个节点时,结果如下,我们发现,增加一个节点对于后面的节点也没有影响,只是前面一个节点需要把指针指向增加的节点。

实现

由于没有直接可用的节点的类型,所以我们需要自定义节点类型如下

public class Node<T> {T data;Node<T> next;public Node(Node<T> n) {next = n;}public Node(T obj, Node<T> n) {data = obj;next = n;}public T getData() {return data;}public Node<T> getNext() {return next;}
}

单链表的代码如下

public class LinkList<T> {private Node<T> head;private int length;//创建单链表public LinkList() {length = 0;head = new Node<T>(null);};//获取头节点public Node<T> getHead() {return head;}//在链表尾增加节点public void add(T object) {Node<T> p, q;p = head;q = head.next;while (q != null) {p = q;q = q.next;}p.next = new Node<T>(object, null);length++;}//插入节点public boolean insert(T object, int position) {if(isEmpty() || position > length) {System.out.println("error");return false;}Node<T> p, q;int i = 1;p = head;q = head.next;while (i < position) {p = q;q = q.next;i++;}p.next = new Node<T>(object, q);length++;return true;}//删除节点public boolean remove(int position) {if(isEmpty() || position > length) {System.out.println("error");return false;}Node<T> p, q;p = head;q = head.next;int i = 1;while (i < position) {p = q;q = q.next;i++;}p.next = q.next;length--;return true;}//清除链表public void clear() {length = 0;head.next = null;}//查找节点public T search(int position) {if(isEmpty() || position > length) {System.out.println("error");return null;}Node<T> p, q;int i = 1;p = head;q = head.next;while (i < position) {p = q;q = q.next;i++;}return  q.data;}//遍历节点public void nextOrder() {if(isEmpty()) {System.out.println("error");}Node<T> p, q;int i = 1;p = head;q = head.next;while (i < length + 1) {p = q;System.out.println(p.data);q = q.next;i++;}}//修改节点public void modify(T object, int position) {if(isEmpty() || position > length) {System.out.println("error");}Node<T> p, q;int i = 1;p = head;q = head.next;while (i < position) {p = q;q = q.next;i++;}q.data = object;}//判断节点是否为空public boolean isEmpty() {return length == 0;}
}

总结

从上面的例子我们可以看出,顺序表的增删很麻烦,只要有一个表项的增加或者删除,后面的表项都需要改变,而对于单链表,增删很方便,对于后面的节点不会有影响。但是对于节点查找,单链表很麻烦,必须要从第一个节点开始遍历,直到找到为止,而对于顺序表而言,查找很方便,只需要给定序号,就可以直接找到,如给定5我们就可以直接找到欧阳娜娜。还是回到我们的原则,因地制宜,没有最好的数据结构,只有最合适的数据结构。

彩蛋

唐朝有个文人叫韦固,小时候经常到河边去玩,一天晚上,他见一个慈祥的老人在月光下翻阅书信,一边看,一边用一根红线绳把两块石头系在一起。韦固看见后非常奇怪,随口问道:“老伯伯,你系石头干什么?”老人说:“我在给当婚的人牵线呢!这一对石头,就是世上一对夫妻呀!“韦固好奇地问:”那我的妻子是谁呢?”老人说:“就是村头看菜园子的女孩儿。”

韦固很生气,心想,那丫头又穷又丑,我可不要,不如害死她算了。第二,他路过菜园,看看旁边没有人,拾了一块石头向女孩砸过去,女孩”扑通”一声倒在地上,韦固也吓得逃往外乡。

十几年后,韦固做了大学士,给他提亲的人非常多,但没有一个称心如意的。一天,韦固到张员外家作客,看见张员外的外甥女美貌出众,心里便十分喜欢;姑娘看韦固仪表堂堂,心里也有几分爱意。张员外看在眼里,喜在心上,当下托媒人定了婚事,选了吉期。到了大喜的日子。韦固将小姐娶到府上。洞房花烛夜,韦固细细端详爱妻,发现额角有一块小疤,就问她是怎么回事。小姐说:“小时候家里穷,有一天,我正在菜园里拾菜,不知哪个野小子打了我一石头,因此留下了这个疤。”韦固听后,心里十分吃惊,就把月下老人的话告诉了妻子,他这才相信缘分是拆不散的。

这就是千里姻缘一线牵的由来,也希望单身的各位都能尽快找到属于自己的姻缘。

点赞就是最大的支持,更多学习资料和文章可以关注微信公众号QStack。

漫谈数据结构系列(二)之千里姻缘一“线”牵相关推荐

  1. 每日 30 秒 ⏱ 千里姻缘一线牵

    简介 SEO.链接.a 标签.HTTP 状态码.link 标签.alternate.canonical 唐朝有个小伙叫韦固喜欢在河边玩,一天遇到一个老伯伯在月光下把两块石头系在一起.小伙看到很好奇便问 ...

  2. 数据结构系列二---[一周leetcode刷题记录]

    2022.2.27 一. 496. 下一个更大元素 I nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素. 给你两个 没有重复元素 ...

  3. 计算机视觉系列(二) - 霍夫线/圆变换

  4. 卜若的代码笔记-数据结构系列-第十二章:栈三.链栈

    1.太简单了,不介绍了,直接贴代码,有问题请看10,11,章 //测试代码public static void main(String[] args) throws IOException {Link ...

  5. 软件开发随笔系列二——关于架构和模型

    软件开发随笔系列二--关于架构和模型 文章目录 软件开发随笔系列二--关于架构和模型 软件模型 功能模型 概念层 边界 参与方 分组分类 逻辑层 功能组织图 层次.模块化 接口 流程模型 概念层 业务 ...

  6. 人工智能算法通俗讲解系列(二):逻辑回归

    2019独角兽企业重金招聘Python工程师标准>>> 今天,我们介绍的机器学习算法叫逻辑回归.它英语名称是Logistic Regression,简称LR. 跟之前一样,介绍这个算 ...

  7. 《CDN 之我见》系列二:原理篇(缓存、安全)

    2019独角兽企业重金招聘Python工程师标准>>> <CDN之我见>共由三个篇章组成,分为原理篇.详解篇和陨坑篇.本篇章适合那些从未接触过.或仅了解一些 CDN 专业 ...

  8. 微服务架构系列二:密码强度评测的实现与实验

    本文是继<微服务架构系列一:关键技术与原理研究>的后续,系列一中论述了微服务研究的背景和意义,主要调研了传统架构的发展以及存在的问题和微服务架构的由来,然后针对微服务架构的设计原则.容器技 ...

  9. Silverlight Blend动画设计系列二:旋转动画(RotateTransform)

    原文:Silverlight & Blend动画设计系列二:旋转动画(RotateTransform) Silverlight的基础动画包括偏移.旋转.缩放.倾斜和翻转动画,这些基础动画毫无疑 ...

最新文章

  1. 我的WEB之路(一)-2.JAVA学习路线
  2. 读取Excel还用POI?试试这款开源工具
  3. emq插件开发mysql_EMQ的Mysql插件
  4. android webview 多文件上传,Android中的webview支持页面中的文件上传实例代码
  5. MySQL数据库之事务
  6. 浅谈移动端页面无刷新跳转问题的解决方案
  7. eclipse git 取远程代码_IDEA中的Git操作,看这一篇就够了!
  8. 2003退休去世领了2年退休金没回本就死了能退吗?
  9. 大数据开发笔记(十):Hbase列存储数据库总结
  10. 2016年1月19日 video.js修改视频源后再调用
  11. 【错误信息】Maximum call stack size exceeded
  12. lasso回归python代码_LASSO回归代码实现 坚韧不拔|静水流深|读书|写作|博雅|数据分析|Python|商业|独立·独特·自立门户 kebook...
  13. 描述性物理海洋学--第一章学习笔记
  14. [BZOJ1233][Usaco2009Open]干草堆tower(单调队列优化)
  15. 架构师学习笔记(四)架构师线路之系统架构师企业架构师
  16. 用 Compose 实现个空调,为你的夏日带去清凉
  17. PHP与JS---取整数方法int,celi,floor,round
  18. sorted与.sort函数及sorted对字典或列表进行排序
  19. 包工协议书样本_工程分包协议书 样本
  20. 以数据中心为核心的RFID资产管理解决方案-新导智能

热门文章

  1. 惠普136w墨粉量低_墨粉量低怎么办
  2. c语言全局变量控制打印线宽的方法,CAD中如何自定义控制图形的打印线宽?
  3. 效果图制作接单平台有哪些?
  4. 老男孩python全栈s21day15作业
  5. Python爬虫基础:安装Scrapy爬虫框架和创建Scrapy爬虫项目
  6. 兴智杯国产开发框架工程化应用赛:齿轮瑕疵检测基线
  7. c语言程序设计第14章在线测试,《C语言程序计》第14章在线测试.doc
  8. 2021年加密货币犯罪报告
  9. 一个简单的例子:通过javascript输出所选择的日期(1)
  10. element时日期选择器禁选某段日期