线性表(list):零个或多个数据元素的有限序列;
l 前驱元素:
l 后继元素:
l 线性表的长度:线性表中元素的个数n;
l 空表:n=0时;
复杂的线性表中,一个数据元素可以有若干个数据项组成;(表格)
建立、清空、获得长度、查找等等;
数组的长度:是存放线性表的存储空间的长度,存储空间分配后这个量一般是不变的;
线性表的长度:线性表中元素的个数,随着线性表插入和删除操作的进行而变化;
线性表的长度小于等于数组的长度;
分配的数组的空间要大于等于当前线性表的长度;
地址:每个储存单元的自己的编号称为地址;
l 插入位置不合理,抛出异常;
l 线性表长度大于等于数组长度,抛出异常或动态增加容量;
l 从最后一个开始遍历到第i个位置,分别将他们向后移动一个位置;
l 将要插入的元素填入位置i处;表长加1;
***JAVA 中的插入方法是:void add ( intindex, Integer element);
l 删除位置不合理,抛出异常;
l 取出删除元素;
l 从删除位置开始遍历到最后一个元素,分别将他们都向前移动一个位置;
l 表长减1;
***线性表的顺序储存结构,读取、存储的时间复杂度是O(1),插入、删除的时间复杂度是O(n),所以比较适合元素个数变化不大,更多的是存储数据的应用;
优点:逻辑关系不用耗费额外的存储空间;
可以快速的存取表中任一位置的元素;
缺点:插入和删除需要移动大量元素;
线性表长度变化较大时,难以确定储存空间的容量;
造成储存空间的“碎片”;
给前边的元素添加后边元素的内存地址索引值;
l 用任意存储单元存储线性表的数据元素,可以连续,可以不连续;
l 链式结构中,要存储数据元素信息+后继元素的存储地址;
l 数据域+指针域,指针中存储的信息称为指针或链;这两部分信息组成数据元素a的存储映像,称为结点(Node);
l N个结点连接成一个链表,即为线性表的链式存储结构;(单链表)
l 链表中的第一个结点的存储位置叫做头指针;
l 单链表的第一个结点前附设一个结点叫头结点,头结点的数据域不存储信息,最后一个结点的指针指向空(null);
l 头指针
n 头指针是链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;
n 头指针具有标识作用,常用头指针冠以链表的名字;
n 无论链表是否为空,头指针不能为空;
l 头结点
n 放在第一元素的结点前,其数据域一般无意义,可用来存放链表的长度;
n 方便对第一元素结点前的数据插入,和第一结点的删除;
n 头结点不是链表必须的;
结点由存放数据元素的数据域和存放后继结点地址的指针域组成;
For instance:
假设p是指向线性表第i个元素的指针,该结点的数据域可以用p->data来表示,值为一个数据元素;指针域可以用p->next表示,值为一个指针,指向第i+1个元素;
查找链表第i个数据的算法思路:(其实就是顺序查找)
l 声明一个指针p指向链表的第一个结点,初始化j从1开始;
l 当j小于i时,遍历链表,p依次向后移动,j累加1;
l 若一直查询到链表结尾还没有找到,则说明第i个结点不存在;
l 否则查找成功,返回结点数据;
核心思想就是,工作指针后移,最坏情况的时间复杂度是O(n);
将元素e插入到结点p和p->next之间的算法思路:
l 生成一个新的结点s;
l 将元素e赋值给s->data;
l 将p的后继结点改成s的后继结点,再把s变成p的后继结点;即
S->next =p->next; p->next = s;(注意两句不能颠倒)
将结点o, p, q 中的p结点删除的算法思路:
l o->next =p->next,即令o->next = q;
l 释放p结点,
单链表和顺序储存结构不同,是一种动态结构,所占空间的大小和位置不需要预先划分,可以根据系统的情况和实际的需求即时生成;
创建单链表的过程是一个动态生成链表的过程,从“空表”的初始状态起,一次建立各个元素结点,并逐个插入链表;
算法思路:
l 声明一个指针p和计数器变量i;
l 初始化一个空链表L;
l 让L的头结点指针指向NULL,即建立一个带头结点的单链表;
l 循环
n 生成一个新节点赋值给p;
n 随机生成一个数字赋值给p的数据域p->data;
n 将p插入到头结点与前一新结点之间;
**这种方法叫--头插法:始终让新结点在第一的位置;
**另一种尾插法:让新节点插在终结点的后面;
即将这个链表在内存中释放掉;
算法思路:
l 声明一个结点p和q;
l 将第一个结点赋值给p;
l 循环:
n 将下一个结点赋值给q;
n 释放p;
n 将q赋值给p;
***注意q的必要性,起到指引下一个删除的元素的作用;
l 存储分配方式:
n 顺序储存结构用一段连续的存储单元依次存储线性表的数据元素;
n 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素;
l 时间性能:
n 查找:O(1)和O(n)
n 插入和删除:O(n)和O(1);
l 空间性能:
n 顺序存储空间需要预分配存储空间;可能造成空间浪费和溢出;
n 单链表不需要分配存储空间,元素个数不受限制;
l 结论:
n 频繁查找,宜采用顺序储存结构;
n 频繁插入和删除,宜采用单链表结构;
n 在预知元素个数的时候,采用顺序存储结构;反之则使用单链表;
某些语言在没有指针的情况下,让数组的每个数据元素由两个数据域组成,data和cur,数据域data,用来存放数据元素,cur相当于单链表中的next指针,存放该元素的后继在数组中的下表,cur叫游标;这种用数组描述的链表叫做静态链表;
第一个元素和最后一个元素做特殊处理,不存数据。把未被使用的数组元素称为备用链表。第一个元素的cur游标存放备用链表的第一个结点的下标;最后一个元素的cur存放第一个有值元素的下标,相当于单链表的头结点;
把要插入的新结点存储在备用链表中(由未被使用过的和已经被删除的分量用游标连接成),改变插入位置前后元素的cur值即可;
让删除的位置成为第一个优先空位,把他存入第一个元素的cur中;
优点:插入和删除时,不需要移动大量元素,只需修改游标;
缺点:表长难以确定;不能随机存取;
将单链表中终端结点的指针由空指针改为指向头结点;
在单链表的每个结点中,都设置一个指向其前驱结点的指针域;(即一共两个指针域,一个指向后继,一个指向前驱);
插入和删除时,需要更改两个指针变量;
l 插入操作:把s插入到p和p->next之间:
S->prior = p;
s->next = p->next;
p->next ->prior = s;
p->next = s;
l 删除操作:删除p->prior和p->next之间的p:
P->prior->next= p->next;
p->next->prior= p->prior;