在我们谈论本文具体内容之前,我们首先要说明一些事情。在现实生活中我们所说的“表”往往是二维的,比如课程表,就有行和列,成绩表也是有行和列。但是在数据结构,或者说我们本文讨论的范围内,我们所说的“线性表”是一维的,即所有“元素”都是前后排列的。就我个人而言,这样的“表”用“队列”来形容比较恰当。但是,数据结构中“队列”这个名词是被一种特殊的“线性表”给占用了的,所以我们没法再用“队列”来表示“线性表”,后期我们会对“队列”进行介绍。

  

  在第一段的说明过程中,我们其实已经说出了“线性表”的定义,就是若集合中的元素在逻辑上是一前一后像队伍一样联系起来的,那么这个集合就是一个表(准确地说是线性表)。

  显然,我们常用的数组就是表的一种,它符合“元素一前一后联系起来”的要求。线性表是最基础的数据结构(虽然结构体也能存多个数据在内,但其整体还是视为一个对象的),每当我们需要存储的数据不存在特殊的关系(比如以后会说的一对多关系),或者存在的关系为“一前一后”时(比如用户输入多个字符,字符间就存在输入顺序上的“一前一后”关系),我们就可以使用线性表。

  那么,线性表的相关知识讲到这儿就算结束了吗?毕竟数组大家应该都会用了。显然不是,我们说了,数组是线性表的一种,但也只是线性表的一种。

  接下来我们就要说说,使用数组作为线性表的缺点。首先让我们假设一种情况(这个在(1)中提到过):

  我们要写一个程序,这个程序的过程很简单:获取用户输入(这里就需要用到表来存储用户的输入),对用户的输入进行计算或操作,输出结果。

  但是这个程序要考虑一个情况:用户有时候只需要输入几个数据,而有时候却需要输入几万个数据(可能有人会说怎么可能输入那么多,人都累死了。。。但是别忘了有一种操作叫文件重定向,虽然我记不得也没用过)。对于C程序来说,这个问题是不得不考虑的,如果你决定使用数组来存储用户的输入,那么数组的大小在创建之时就要确定好。很显然,数组的大小很好确定,比如十万,反正绝对大于用户可能的输入数量就行。但是这会带来一个很严重的问题,就是你的程序在不需要那么多空间的情况下依然会使用那么多空间,比如用户平均输入只有几百个,然而每次运行程序都先占用了十万大小的数组空间。显然这样的程序很不好,一来用户的内存可能还有别的程序需要使用,二来可能别的用户不需要十万个的存储空间而且他的内存也不够。

  那么对于这种情况,我们该怎么办呢?

  首先我们发现我们依然要用到线性表(假设用户的输入数据间的关系就是一前一后),所以我们先确定下来使用的是线性表类型的数据结构。然后我们希望的关键点其实就是:线性表能够随着需要而改变大小。那么我们该如何实现这样一个线性表呢?现在,不需要你去思考解决方案了,我们已经有了现成的数据结构,那就是链表!

  回顾数组,我们发现,其实我们知道的信息有两个:

  1.数组第一个元素在哪(数组名)

  2.数组中元素都是相邻的,后一个元素就在前一个元素的后面,中间没有“空”

  因为我们知道这两个信息,所以我们不需要知道各个元素的具体位置,只要根据某个元素在线性表中的顺序位置n,就可以由第一个元素的位置加上n来得到该元素。

  但这也正是数组的不足所在,为了满足第2点,我们必须在创建数组时就指定其大小,只有这样我们才能找到满足2的一整块区域给数组。那么,为了解决这个不足,我们要做的就是不再使用一整块区域,而是令各元素自取所需。即元素不一定是相邻的了,只要添加元素时找一个可以放下该元素的容身之所就行,这一点的实现显然是利用malloc()。

  但这又会带来一个问题,由于各元素都是通过malloc()获取的内存,所以各元素都分散开了,那么我们该如何找到各元素呢?实现的办法很简单,就是令每个元素“记住”下一个元素的位置!这样一来,我们就只需要保存第一个元素的位置就可以了,第二个元素的位置在第一个元素中,第三个元素的位置又在第二个元素中,以此类推。

  接下来我们要做的,就是将这个想法付诸实现了。相信很快,我们就会发现,实现链表的关键之处在于如何“令元素记住下一个元素的位置”?在这里我们要多嘴一句,正如第一篇博文所说的,数据结构不仅决定如何存储数据,有时候也要决定或者说不得不考虑“存储什么数据”。现在我们就遇上了这样的问题。显然,原始元素本身是不会记住下一个元素在哪的,比如原始元素类型为int,它又如何去记住下一个int在哪?这时候,我们就需要对数据“封装”一下,形成一种新的数据类型,然后这种数据类型要能够记住下一个相同数据类型的位置。

  思路已经出来了,就是“封装”出新的数据类型,然后要求其能记住下一个相同数据类型数据的位置。“封装”可以令我们想到结构体(也许你想不到但没关系,现在知道了),而“位置”则会让我们想到指针。因此我们“封装”出来的新数据类型应该是一个类似这样的结构体:

struct  Element
{
DataType data; //DataType根据实际元素类型决定
struct Element * next; //next意味着其存储下一个元素的位置
}

  然后在我们的程序中,我们只需要知道第一个元素在哪就行了(第一个会告诉我们第二个在哪,以此类推):

struct  Element  a={data,NULL};
struct Element * List=&a; //这个List就是一个“链表”

  现在,对于为什么要使用链表,以及链表该如何实现的基本思想及如何“封装”出链表的元素我们应该都明白了。

  但是虽然知道了链表添加新元素时该怎么做已经有了口头上的描述,却还没有给出代码上的实现,并且如何从链表中删除一个元素以及如何找到第n个元素也还没给出实现。

  这些可以统称为对链表的操作,也可以说是能对链表这种数据结构使用的算法。关于这些,我们将在下一次博文中介绍。

深入浅出数据结构C语言版(4)——表与链表的更多相关文章

  1. 深入浅出数据结构C语言版(5)——链表的操作

    上一次我们从什么是表一直讲到了链表该怎么实现的想法上:http://www.cnblogs.com/mm93/p/6574912.html 而这一次我们就要实现所说的承诺,即实现链表应有的操作(至于游 ...

  2. 数据结构C语言版 有向图的十字链表存储表示和实现

    /*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...

  3. 深入浅出数据结构C语言版(6)——游标数组及其实现

    在前两次博文中,我们由表讲到数组,然后又由数组的缺陷提出了指针式链表(即http://www.cnblogs.com/mm93/p/6576765.html中讲解的带有next指针的链表).但是指针式 ...

  4. 深入浅出数据结构C语言版(7)——特殊的表:队列与栈

    从深入浅出数据结构(4)到(6),我们分别讨论了什么是表.什么是链表.为什么用链表以及如何用数组模拟链表(游标数组),而现在,我们要进入到对线性表(特意加了"线性"二字是因为存在多 ...

  5. 深入浅出数据结构C语言版(1)——什么是数据结构及算法

    在很多数据结构相关的书籍,尤其是中文书籍中,常常把数据结构与算法"混合"起来讲,导致很多人初学时对于"数据结构"这个词的意思把握不准,从而降低了学习兴趣和学习信 ...

  6. 深入浅出数据结构C语言版(8)——后缀表达式、栈与四则运算计算器

    在深入浅出数据结构(7)的末尾,我们提到了栈可以用于实现计算器,并且我们给出了存储表达式的数据结构(结构体及该结构体组成的数组),如下: //SIZE用于多个场合,如栈的大小.表达式数组的大小 #de ...

  7. 深入浅出数据结构C语言版(10)——树的简介

    到目前为止,我们一直在谈论的数据结构都是"线性结构",不论是普通链表.栈还是队列,其中的每个元素(除了第一个和最后一个)都只有一个前驱(排在前面的元素)和一个后继(排在后面的元素) ...

  8. 深入浅出数据结构C语言版(12)——从二分查找到二叉树

    在很多有关数据结构和算法的书籍或文章中,作者往往是介绍完了什么是树后就直入主题的谈什么是二叉树balabala的.但我今天决定不按这个套路来.我个人觉得,一个东西或者说一种技术存在总该有一定的道理,不 ...

  9. 深入浅出数据结构C语言版(14)——散列表

    我们知道,由于二叉树的特性(完美情况下每次比较可以排除一半数据),对其进行查找算是比较快的了,时间复杂度为O(logN).但是,是否存在支持时间复杂度为常数级别的查找的数据结构呢?答案是存在,那就是散 ...

随机推荐

  1. Vmware 中安装 Ubuntu Server (或者ubuntu 以文本界面登陆时) 分辨率无法全屏问题

    Vmware 中安装 Ubuntu Server/Ubuntu 分辨率,无法全屏问题 需要更改grub设置 在终端或者文本界面按下列步骤进行设置: 第一步: 输入命令 sudo vim /etc/de ...

  2. ES2:ElasticSearch 集群配置

    ElasticSearch共有两个配置文件,都位于config目录下,分别是elasticsearch.yml和logging.yml,其中,elasticsearch.yml 用来配置Elastic ...

  3. C# 6 与 .NET Core 1.0 高级编程 - C# 6 改进

    个人原创译文,转载请注明出处.有不对的地方欢迎指出与交流. 英文原文:Professional C# 6 and .NET Core 1.0 - What's New in C# 6 C# 6 改进 ...

  4. [html] 学习笔记--Web存储

    HTML5 提供了两种在客户端存储数据的新方法之前,这些都是由 cookie 完成的.但是 cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效 ...

  5. 763A - Timofey and a tree

    A. Timofey and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  6. iOS中的三大定时器

    iOS开发中定时器经常会用到,iOS中常用的定时器有三种,分别是NSTime,CADisplayLink和GCD. NSTimer 方式1 // 创建定时器 NSTimer *timer = [NST ...

  7. css经典布局之左侧固定大小右侧自动适应

    最近学习了一种经典布局,固定左侧或右侧的宽度,另一侧自适应宽度,此种布局挺常用,尤其是像后台,大部分都是采用这种结构,还比如像订餐类的APP,进入商家的时候,会出现一堆饭的列表,左侧是饭的分类,右侧是 ...

  8. C语言的函数类型

    C语言的函数类型与返回值类型不一致时出现,是以函数类型为标准; 而如果在java与c#语言中上述情况是编译错误的;

  9. 《javascript个人理解,个人整理。》

    万事开头难. 本人做前端工程师,已几年,没有特别大的,已文字方式去做总结. 前段时间,早已经想好,但是迟迟没有去下笔!好在现在陆陆续续的写下去. 我知道这是一个很大的工程,但是我还是想做下去,不为别的 ...

  10. 初学jQuery之jQuery事件与动画

    今天我们就谈谈jquery中的事件和简单动画吧,它们毕竟基础是进阶华丽的根本!! 1.事件 1.window事件 ready   准备就绪 2.鼠标事件 方法                      ...