初识数据结构
如何在书架上摆放图书
Q1:如何插入新书?
Q2:如何找到某本指定的书?
- 随便放(所有新数据均插入最后)
A1:放置简单 一步到位
A2:从第一本书往后遍历 工作量巨大 - 按书名字母顺序排放
A2:二分查找 取位于中间的那本书看首字母判断所需书在那一边 以此类推
A1:将新书首字母后的书全部后移一位 给新书留出位置 工作量大 - 将书分类 再按首字母排列
A1:先定类别 在该类别中二分法找位置 再移书
A2:先定类别 再用二分法找书
解决问题方法的效率,跟数据的组织方法有关
写程序实现一个函数PrintN,顺序打印1~N
- 循环实现
{
int i ;
for ( i=1 ; i<=N ; i++ )
{
printf ("%d\n", i ) ;
}
return ;
}
- 递归实现
{
if ( N )
{
PrintN ( N - 1 ) ;
printf("%d\n", N ) ;
}
return ;
}
如果N过大 递归会因内存满了而不输入任何东西(空间占用大)
解决问题方法的效率,跟空间利用效率有关
解决问题方法的效率,跟算法的巧妙程度有关
(计算机初学者,只记录思路,尽量不展示代码)
- 数据对象是在计算机中的组织方式
- 数据对象必定与一系列加在其上的操作相关联
- 完成这些操作所用的方法就是算法
抽象数据类型
数据类型
- 数据对象集
- 数据集合将关联的操作集
抽象
描述数据类型的方法不依赖于具体实现
- 与存放数据的机器无关
- 与数据存储的物理结构无关
- 与实现操作的算法和编程语言无关
描述数据类型“是什么”
算法
- 一个有限指令集
- 可接受一些输入
- 产生输出
- 一定在有限步骤后终止
- 每一条指令必须
- 有充分明确的目标,不可有歧义
- 计算机能够处理的范围内
描述数据类型“如何实现”
空间复杂度S(n)
根据算法写成的程序在执行时占用存储单元的长度
时间复杂度T(n)
根据算法写成的程序在执行时耗费时间的长度
长度往往与输入数据的规模与关
Tworth(n) 最坏情况复杂度
Tavg(n)平均复杂度
一般以最坏情况复杂度为准
例题
给定N个整数的序列,求连续x项子列和的最大值
算法一
暴力求解 算出所有情况,取最大值
算法二
开头一样时,直接累加比较即可
算法三 分而治之
从中间分开
递归的求出两边最大的子列和各是多少
所求就在这两个和跨越边界的子列和之
算法四 在线算法
从第一项往后遍历,maxsum从零开始加A[i]项
如果结果小于零,就将maxsun归零
否则比较thinsun和maxsun,maxsun取其最大值
在线的意思是指每输入一个数,就能进行即时处理,在任何一个地方终止输入,算法都能正确给出当前的解。
多项式的表示
多项式的关键信息
- 多项式项数 n
- 各项系数 ai及指数 i
法一:顺序存储结构直接表示
数组各分量对应多项式各项
i为指数 a[i]为系数
问题:表示x+3x2000 太麻烦,需要大量空间
法二:顺序存储结构表示非零项
将每个多项式看成是一个(a,i)二元组的集合 结构数组
多项式相加:按两个数组分别按指数大小降序排列,从第一位开始比较,指数大的输出,相等相加,相应位数加一,继续比较。
法三:链表结构存储非零项
链表中每个结点存储多项式中的一个非零项,包括系数、指数两个数据域以及一个指针域
coef | expon | link |
---|
同一个问题可以又不同的表示(存储)方法
有一类共性问题:有序线性序列的组织和管理
线性表(Linear List)
由同类型数据元素构成有序序列的线性结构
- 表中元素个数称为线性表的长度
- 线性表没有元素时,称为空表
- 表起始位置称为表头,结束位置为表尾
数据对象集:线性表是n(不为零)个元素构成的有序序列
操作集:线性表L∈List,整数i表示位置,元素x∈ElementType, - 常用函数
- **List MakeEmpty()**初始化一个空线性表L
- **ElementType FindKth( int K , List L )**根据位序K,返回相应元素
- **int Find( ElementType X , int i , List L )**在线性表L中查找X的第一次出现的位置
- **void Insert( ElementType x , int i , List L )**在位序i前插入一个新元素X
- **void Delete(int i , List L )**删除指定位序i的元素
- **int Length( List L )**返回线性表L的长度n
线性表的顺序存储实现
利用数组的连续存储空间顺序存放线性表的各元素
主要操作的实现
- 初始化(建立空的顺序表,指针设为-1即为空;为0 则为第一位)
- 查找(遍历,比较,若找到了即返回x;没找到返回-1)
- 插入(在第i个位置插入一个值为X的新元素)(要把i以后的元素都往后挪)
- 删除(删除第i个位置上的元素)(要把i后的元素前移)
线性表的链式储存实现
不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建立起数据元素之间的逻辑关系。
插入、删除不需要移动数据元素,只需要修改“链”。
主要操作的实现
-
求表长(遍历一遍,计数器)
-
查找
- 按序号查找:FindKth(遍历、比较)
- 按值查找:Find
-
插入(在第i-1个结点后插入一个值为X的新结点)
- 先构造一个新的节点,用s指向
- 再找到链表第i-1个结点,用p指向
- 修改指针,插入结点(p后插入新结点s)
s->Next = p->Next;
p->Next = s;
-
删除(删除链表的第i个位置上的结点)
- 找到链表的第i-1个结点,用p指向
- 用指针s指向要被删除的结点
- 修改指针,删除s所指的结点
s = p->Next
p->Next = s->Next - 释放s所占用的空间
free(s)
二元多项式的表示
广义表
- 广义表是线性表的推广
- 对于线性表而言,n个元素都是基本的单元素
- 广义表中,这些元素不仅可以是单元素也可以是另一个广义表
对于一个二元多项式,可将其看作一个一元多项式,暂时将另一个变量看作常数,按一元多项式方法求解;对于系数,也可以分别看做一个个一元多项式,用指针链起来。(复杂链表)
指针相当于链条 将一个结点连向另一个结点
多重链表:链表中的结点可能同时隶属于多个链
- 多重链表中结点的指针与会有多个,但包含两个指针域的链表不一定是多重链表。
堆栈
用途
- 表达式求解
- 递归
组成
- 运算数
- 运算符(有优先级)
后缀表达式求值
- 6 2 / 3 - 2 * + =
从左到右扫描,记住未参加运算的数,遇到运算符,将距离最近的两个数运算
先放的后拿出,后放的先拿出
堆栈的抽象数据类型描述
堆栈(stack):具有一定操作约束的线性表。只在一端(栈顶,top)做插入、删除
插入数据:入栈(push)
删除数据:出栈(pop)
后入先出:last in first out
数据对象集:一个有0或多个元素的又穷线性表
操作集:长度为MaxSise的堆栈S∈ElementType
- Stavk CreateStack( int MaxSize):生成空堆栈,最大长度为MaxSize
- int IsFull( Stack S , int MaxSize ):判断堆栈S是否已满
- void Push( Stack S , ElementType item ):将元素item压入堆栈
- int IsEmpty( Stack S ):判断堆栈S是否为空
- ElementType Pop( Stack S ):删除并返回栈顶元素
堆栈的链式存储实现
堆栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行。