线性结构的概念:
①存在唯一的“第一个”元素,存在唯一的“最后一个”元素;
②除第一个之外,集合中的每个元素均只有一个前驱;③除最后一个之外,集合中的每个元素均只有一个后继。
线性表是由n个数据元素构成的有限序列。
至于每个元素的具体含义,它可以是一个数值,或一个符号,也可以是一页书,以及代表其他更复杂的信息。
我个人把表的实现方式分成三大类:
1. 纯数组表
2. 链式数组表
3. 纯链表
1. 纯数组表特征:
① 固定大小,表的长度事先已知。② 适合随机遍历(存取),查找与排序。
③ 因为只知道最大长度,无法进行插入或删除操作;或者要做增减也非常困难。
int array-list[5] ={12 , 4 ,36 ,80 ,1 };
array-list就是一个满元素的纯数组表,元素个数为5,表的长度也是5。
它的第一个元素值为 【12】,最后一个元素值为 【1】。
通过最大表长(避免越界),我们就能轻松的遍历,查找与排序。
同时,这种表无法进行插入或删除元素的操作。
而
int list[15] ={12 , 4 ,36 ,80 ,1 };
就是一个不满元素的纯数组表,元素个数为5,表的长度为15,没有被赋值的元素部分充斥着“垃圾值”,对它进行遍历,查找是毫无意义的。
尽管我们可以通过数数的方式,知道当前元素的个数为5,但是如果元素更多呢?元素是更复杂的聚合类型呢?
再通过人工数数的方式,显然不可能实现;因此我们需要把当前元素的个数单独保存。
第一种改进方法就是把当前元素个数的值保存在第一个元素空间里。
int list[15] ={5, 12, 4 ,36 ,80 ,1 };
这样我们就知道,表的最大长度为15,元素个数为5,通过读取第一个元素,就能避免数组越界,对表进行正确的遍历,查找和排序了。
简单的整型数据元素可以这样做,如果是浮点数呢?甚至是复杂的聚合类型呢?
float list[15] ={5, 2.58, 4.71 , 36.12 , 80.66 , 1.13 }; //错误写法,元素个数不能是浮点值</span>
表的长度也许有300,当前元素个数为4,当前元素的个数值应该保存在哪里?
而且该表的元素类型为 student , 元素个数类型为 int,不同类型是无法保存在一起的。
第二种改进方法就是设定一个结尾标记,思想类似于c语言中的字符串。
通过结尾标记,就能知道当前元素的个数,避免数组越界。
但是这种方法也有缺点,首先每次遍历都必须与结尾标记进行“比较判断”,假设有500个数据,就要判断500次,这无疑增大了额外开销;其次在于结尾标记的选择,必须是不会和原始数据产生二义性。
同样这种方法也无法解决不同数据类型的糅合。
2. 链式数组表
纯数组表有许多缺陷,包括它的两个改进型,只适合用在数据量小,数据类型简单的情况下。
当前元素的个数需要被保存,但在复杂聚合类型的情况下,又无法糅合在一起。
于是人们干脆分开它们,分别保存。
也就产生了:链式数组思想。
左边的“数组”用来保存各种额外信息,而右边的数组保存数据元素。
要访问数组表的时候,通过指针指向数组的首地址来间接访问。
这样一来,灵活性大大增强,左边“数组”可以随意增添我们需要的信息。
即解决了复杂类型的糅合问题,也无需多次判断,提高了效率。
额外的信息都有相互不同的数据类型,左边“数组”更准确的表示应该为“结构体”。
这种灵活性同样体现在“右边”数组,既可以用固定大小表示:
int list[15] ={12, 4 ,36 ,80 ,1 };
又可以使用malloc 动态分配,这样就实现了不固定大小:
(elemtype *) malloc( list-maxlength * sizeof (elemtype) )