【C++数据结构学习笔记】一、线性表(课件+总结)

1.1 线性表的定义和特点

线性表(List):零个或多个具有相同特性的数据元素的有限序列

又或者定义为:由n(n>=0)个数据元素(结点)a1,a2,…,an组成的有限序列

关键词:有限 零个或多个 相同特性 数据元素

请添加图片描述

上图中标注的各个部分都是线性表不可缺少的重要元素。并且,每个数据元素都最多有一个直接前驱和直接后继,这也是判断某数据结构是否为线性表的重要条件。

线性表分为两种:顺序表链表,而链表有单链表,循环链表,双链表多种

顺序表采用的是顺序存储结构和随机存取,链表采用的是链式存储结构和顺序存取,关于随机存取和顺序存取,后面会说到。

1.2 案例引入

1.2.1 一元多项式的运算

对于简单的一元多项式运算(即最高次数较低的),我们可以用数组存储各项的指数与系数,注意:此时的指数是将其作为下标存在数组内,因此,数组内会含有零项,因此,如果指数过大(比如几千几万,而中间的指数也并不是从1一直连续加到这个很大的数,数组中就会存在很多零项(系数为0)),那么就会造成不必要的内存浪费。
请添加图片描述

请添加图片描述

1.2.2 稀疏多项式的运算

为了解决1.2.1中可能出现的内存浪费的情况,我们将指数单独存放,并且只存放非零项(见下图)通过这种方式创建出来的线性表即为顺序表,其物理结构为顺序存储结构在此基础上,我们就可以很方便的表示出稀疏多项式,并通过创建新的数组来存放两个多项式运算后的结果。

请添加图片描述

请添加图片描述

但是问题又来了,我们在运算之前,该怎么确定数组的大小,才能避免不必要的内存空间的浪费呢?这就需要一种链式存储结构来解决这种问题。从下图中也可以清楚地看到链式存储结构对于存储空间的分配更加灵活(有多少就分配多少)。
请添加图片描述

有了链表,我们就可以在不浪费存储空间的前提下更加方便地表示出多项式的相加了。
请添加图片描述

1.2.3 图书信息管理系统

图为“图书管理系统”的逻辑结构,图书表可以抽象为一个线性表(想一想线性表的特点),表中的每条记录都是线性表中的数据元素。

请添加图片描述

图为“图书管理系统”的顺序表链表的两种表示

请添加图片描述

以下是图书表的顺序存储结构的类型定义

#define MAXSIZE 10000 //图书表可能达到的最大长度

//图书信息定义
typedef struct
{
  char no[20];//图书ISBN
  char name[50];//图书名字
  float price;//图书价格
}Book;

typedef struct
{
  Book *elem;//存储空间基地址
  int length;//图书表中当前的图书个数
}SqList;

小tips: SqList的全称为sequence list,即为顺序表

1.2.4 总结

通过以上几个案例的分析,可以做出相应总结:

  • 线性表中数据元素的类型可以为简单类型,也可以为复杂类型
  • 许多实际应用问题所涉及的基本操作有很大的相似性,不应为每个具体应用单独编写一个程序。
  • 从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作

1.2.5 案例补充说明

补充一:类型说明

下面用到了typedef定义数据类型,如果你不太熟悉,可以去CSDN里直接搜索typedef的用法就行了,网上总结的很全面。

typedef char ElemType

typedef struct
{
  ElemType data[];
  int length;
}SqList;
typedef struct
{
  float p;
  int e;
}Polynomial;

typedef struct
{
  Polynomial *elem;
  int length;
}SqList;

补充二:数组定义

首先是数组的静态分配

typedef struct
{
  ElemType data[MAXSIZE];
  int length;
}SqList;

然后就是数组的动态分配

typedef struct
{
  ElemType *data;
  int length;
}SqList;

SqList L;
L.data = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE);

如果你不太懂数组的动态分配中malloc是什么东西,没关系,往下看,我们来复习一下。

补充三:C语言的动态内存分配

请添加图片描述
补充四:C++的动态内存分配

请添加图片描述
从上面可以看出,C++的动态内存分配的代码还是很简洁的。

1.4线性表的类型定义(抽象数据类型)

请添加图片描述

1.5 线性表的顺序表示和实现

1.线性表的顺序表示又称为顺序存储结构顺序映像

请添加图片描述

下面举一个简单的小栗子

请添加图片描述

再来看看顺序表中存储位置的计算

请添加图片描述

2.顺序表的实现,即基本操作

先来看几个简单操作

//线性表L的初始化
Status InitList_Sq(SqList &L)
{
  L.elem = new ElemType[MAXSIZE];
  if(!L.elem)
    exit(OVERFLOW);//存储分配失败
  L.length=0;
  return OK;
}
//销毁线性表L
void DestoryList(SqList &L)
{
  if(L.elem)
    delete L.elem;
}
//清空线性表L
void ClearList(SqList &L)
{
  L.length=0;
}

再来看看使用频率比较高的算法

a.顺序表的查找

请添加图片描述
相应的算法分析:
请添加图片描述

b.顺序表的插入

请添加图片描述

请添加图片描述
相应的算法分析:
请添加图片描述

c.顺序表的删除

请添加图片描述
请添加图片描述
相应的算法分析:

请添加图片描述

1.6 线性表的链式实现和表示

1.6.1 链表的相关介绍

先来看一下链表的相关说明:

  • 用一组物理位置任意的存储单元来存放线性表的数据元素
  • 这组存储单元既可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的
  • 链表中元素的逻辑次序和物理次序不一定相同

请添加图片描述

与链式存储的相关术语:

请添加图片描述
头指针是链表的必要元素,但头结点不是请添加图片描述
看到这你可能会问:既然头结点不是必要的,在链表中设置头结点有什么好处呢?
请添加图片描述
那么,头结点的数据域内装的是什么呢?
请添加图片描述

搞清楚以上的一些术语后,让我们来看看链表的存储结构示意图,一般有以下两种形式:

请添加图片描述
链表有很多种形式,这里我们重点分析其中的三种:单链表,循环链表,双链表
在这里插入图片描述

1.6.2 单链表

这里我们分析带头结点的单链表
请添加图片描述
单链表的存储结构如下:
请添加图片描述

单链表的实现(基本操作)

1.单链表的初始化

请添加图片描述

2.判断链表是否为空

请添加图片描述

3.单链表的销毁

请添加图片描述
请添加图片描述

4.清空单链表

请添加图片描述

请添加图片描述

5.求单链表的表长

请添加图片描述

请添加图片描述

6.单链表取值

请添加图片描述
请添加图片描述

7.删除元素

请添加图片描述

请添加图片描述

请添加图片描述

8.查找之按值查找(获取元素的位置序号)

请添加图片描述

9.查找之按地址查找(返回元素的地址)

请添加图片描述

1.6.3循环链表

先来看一下循环链表的定义:
请添加图片描述

请添加图片描述

从下图对比的时间复杂度可以看出,在循环链表中添加尾指针比添加头指针更加方便请添加图片描述

带尾指针的链表的合并

请添加图片描述

请添加图片描述

1.6.4双向链表

请添加图片描述
请添加图片描述

请添加图片描述

双向链表的插入

请添加图片描述

请添加图片描述

双向链表的删除

请添加图片描述
请添加图片描述

1.6.5三种链表的时间效率的比较

请添加图片描述

1.7 顺序表和链表的比较

请添加图片描述
嗯?存储密度是什么玩意儿,别急,往下看:

请添加图片描述
下面,我们从空间和时间分别对顺序表和链表做出比较
请添加图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值