《大话数据结构》学习笔记--chapter 3

来源:互联网 发布:实矩阵有实SVD分解 编辑:程序博客网 时间:2024/05/16 07:56

chap 3     线性表

3.2 线性表的定义

       线性表(list):零个或多个数据元素的有限序列;

l  前驱元素:

l  后继元素:

l  线性表的长度:线性表中元素的个数n;

l  空表:n=0时;

复杂的线性表中,一个数据元素可以有若干个数据项组成;(表格)

 

3.3 线性表的抽象数据类型(操作)

建立、清空、获得长度、查找等等;

 

3.4 线性表的顺序储存结构

3.4.1 定义:用一段地址连续的存储单元依次存储线性表的数据元素;

3.4.2 顺序存储方式:一维数组;

3.4.3 数据长度与线性表长度的区别:

       数组的长度:是存放线性表的存储空间的长度,存储空间分配后这个量一般是不变的;

       线性表的长度:线性表中元素的个数,随着线性表插入和删除操作的进行而变化;

       线性表的长度小于等于数组的长度;

3.4.4 地址计算方法:

       分配的数组的空间要大于等于当前线性表的长度;

       地址:每个储存单元的自己的编号称为地址;

 

3.5 顺序储存结构的插入与删除

 

3.5.1 获得元素操作:

3.5.2 插入操作:

l  插入位置不合理,抛出异常;

l  线性表长度大于等于数组长度,抛出异常或动态增加容量;

l  从最后一个开始遍历到第i个位置,分别将他们向后移动一个位置;

l  将要插入的元素填入位置i处;表长加1;

***JAVA 中的插入方法是:void add ( intindex, Integer element);

3.5.3 删除操作:

l  删除位置不合理,抛出异常;

l  取出删除元素;

l  从删除位置开始遍历到最后一个元素,分别将他们都向前移动一个位置;

l  表长减1;

***线性表的顺序储存结构,读取、存储的时间复杂度是O(1),插入、删除的时间复杂度是O(n),所以比较适合元素个数变化不大,更多的是存储数据的应用;

3.5.4 线性表顺序存储结构的优缺点:

       优点:逻辑关系不用耗费额外的存储空间;

                     可以快速的存取表中任一位置的元素;

       缺点:插入和删除需要移动大量元素;

                     线性表长度变化较大时,难以确定储存空间的容量;

                     造成储存空间的“碎片”;

 

3.6 线性表的链式储存结构

3.6.1 顺序储存结构不足的解决办法:

       给前边的元素添加后边元素的内存地址索引值

3.6.2 线性表链式存储结构定义:

l  用任意存储单元存储线性表的数据元素,可以连续,可以不连续

l  链式结构中,要存储数据元素信息+后继元素的存储地址;

l  数据域+指针域,指针中存储的信息称为指针或链;这两部分信息组成数据元素a的存储映像,称为结点(Node);

l  N个结点连接成一个链表,即为线性表的链式存储结构;(单链表)

l  链表中的第一个结点的存储位置叫做头指针

l  单链表的第一个结点前附设一个结点叫头结点,头结点的数据域不存储信息,最后一个结点的指针指向空(null);

3.6.3 头指针和头结点的异同:

l  头指针

n  头指针是链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;

n  头指针具有标识作用,常用头指针冠以链表的名字;

n  无论链表是否为空,头指针不能为空;

l  头结点

n  放在第一元素的结点前,其数据域一般无意义,可用来存放链表的长度;

n  方便对第一元素结点前的数据插入,和第一结点的删除;

n  头结点不是链表必须的;

3.6.4 线性链式储存结构的代码描述:

       结点由存放数据元素的数据域和存放后继结点地址的指针域组成;

       For instance:

假设p是指向线性表第i个元素的指针,该结点的数据域可以用p->data来表示,值为一个数据元素;指针域可以用p->next表示,值为一个指针,指向第i+1个元素;

 

3.7 单链表的读取

       查找链表第i个数据的算法思路:(其实就是顺序查找)

l  声明一个指针p指向链表的第一个结点,初始化j从1开始;

l  当j小于i时,遍历链表,p依次向后移动,j累加1;

l  若一直查询到链表结尾还没有找到,则说明第i个结点不存在;

l  否则查找成功,返回结点数据;

核心思想就是,工作指针后移,最坏情况的时间复杂度是O(n);

 

3.8 单链表的插入

       将元素e插入到结点p和p->next之间的算法思路:

l  生成一个新的结点s;

l  将元素e赋值给s->data;

l  将p的后继结点改成s的后继结点,再把s变成p的后继结点;即

S->next =p->next; p->next = s;(注意两句不能颠倒)

 

3.8 单链表的删除

       将结点o, p, q 中的p结点删除的算法思路:

l  o->next =p->next,即令o->next = q;

l  释放p结点,

 

3.9 单链表的创建

       单链表和顺序储存结构不同,是一种动态结构,所占空间的大小和位置不需要预先划分,可以根据系统的情况和实际的需求即时生成;

       创建单链表的过程是一个动态生成链表的过程,从“空表”的初始状态起,一次建立各个元素结点,并逐个插入链表;

       算法思路:

l  声明一个指针p和计数器变量i;

l  初始化一个空链表L;

l  让L的头结点指针指向NULL,即建立一个带头结点的单链表;

l  循环

n  生成一个新节点赋值给p;

n  随机生成一个数字赋值给p的数据域p->data;

n  将p插入到头结点与前一新结点之间;

**这种方法叫--头插法:始终让新结点在第一的位置;

**另一种尾插法:让新节点插在终结点的后面;

 

3.10 单链表的整表删除

       即将这个链表在内存中释放掉;

       算法思路:

l  声明一个结点p和q;

l  将第一个结点赋值给p;

l  循环:

n  将下一个结点赋值给q;

n  释放p;

n  将q赋值给p;

***注意q的必要性,起到指引下一个删除的元素的作用;

 

3.11 单链表结构与顺序存储结构优缺点

l  存储分配方式:

n  顺序储存结构用一段连续的存储单元依次存储线性表的数据元素;

n  单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素;

l  时间性能:

n  查找:O(1)和O(n)

n  插入和删除:O(n)和O(1);

l  空间性能:

n  顺序存储空间需要预分配存储空间;可能造成空间浪费和溢出;

n  单链表不需要分配存储空间,元素个数不受限制;

l  结论:

n  频繁查找,宜采用顺序储存结构;

n  频繁插入和删除,宜采用单链表结构;

n  在预知元素个数的时候,采用顺序存储结构;反之则使用单链表;

 

3.12 静态链表:

       某些语言在没有指针的情况下,让数组的每个数据元素由两个数据域组成,data和cur,数据域data,用来存放数据元素,cur相当于单链表中的next指针,存放该元素的后继在数组中的下表,cur叫游标;这种用数组描述的链表叫做静态链表;

       第一个元素和最后一个元素做特殊处理,不存数据。把未被使用的数组元素称为备用链表。第一个元素的cur游标存放备用链表的第一个结点的下标;最后一个元素的cur存放第一个有值元素的下标,相当于单链表的头结点;

 

3.12.1 静态链表的插入操作:

       把要插入的新结点存储在备用链表中(由未被使用过的和已经被删除的分量用游标连接成),改变插入位置前后元素的cur值即可;

3.12.2 静态链表的删除操作:

       让删除的位置成为第一个优先空位,把他存入第一个元素的cur中;

3.12.3 静态链表的优缺点:

优点:插入和删除时,不需要移动大量元素,只需修改游标;

缺点:表长难以确定;不能随机存取;

 

3.13 循环链表:

       将单链表中终端结点的指针由空指针改为指向头结点;

 

3.14 双向链表:

       在单链表的每个结点中,都设置一个指向其前驱结点的指针域;(即一共两个指针域,一个指向后继,一个指向前驱);

       插入和删除时,需要更改两个指针变量;

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;