传智播客C和C++与数据结构基础讲义.docx
- 文档编号:26005656
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:79
- 大小:6.13MB
传智播客C和C++与数据结构基础讲义.docx
《传智播客C和C++与数据结构基础讲义.docx》由会员分享,可在线阅读,更多相关《传智播客C和C++与数据结构基础讲义.docx(79页珍藏版)》请在冰豆网上搜索。
传智播客C和C++与数据结构基础讲义
传智播客C和C++与数据结构基础讲义
传智扫地僧
1、数据结构概念
1.1数据结构相关概念
1.1.1疑惑
1、我学完了C语言,可是现在感觉还是写不出代码。
2、为什么会有各种各样的程序存在?
3、程序的本质是什么?
程序是为了具体问题而存在的
程序需要围绕问题的解决进行设计
同一个问题可以有多种解决方案
如何追求程序的“性价比”?
是否有可量化的方法判别程序的好坏?
1.1.2数据结构起源
计算机从解决数值计算问题到解决生活中的问题
现实生活中的问题涉及不同个体间的复杂联系
需要在计算机程序中描述生活中个体间的联系
数据结构主要研究非数值计算程序问题中的操作对象以及它们之间的关系
不是研究复杂的算法
1.1.3数据结构中的基本概念
数据–程序的操作对象,用于描述客观事物(inta,intb,)
数据的特点:
可以输入到计算机
可以被计算机程序处理
数据是一个抽象的概念,将其进行分类后得到程序设计语言中的类型。
如:
int,float,char等等
数据元素:
组成数据的基本单位
数据项:
一个数据元素由若干数据项组成
数据对象–性质相同的数据元素的集合(比如:
数组,链表)
//友情提示,来自结构体课堂代码
//声明一个结构体类型
struct_MyTeacher//一种数据类型
{
charname[32];
chartile[32];
intage;
charaddr[128];
};
intmain21()
{
struct_MyTeachert1;//数据元素
struct_MyTeachertArray[30];//数据对象
memset(&t1,0,sizeof(t1));
strcpy(t1.name,"name");//数据项
strcpy(t1.addr,"addr");//数据项
strcpy(t1.tile,"addr");//数据项
t1.age=1;
}
数据元素之间不是独立的,存在特定的关系,这些关系即结构
数据结构指数据对象中数据元素之间的关系
如:
数组中各个元素之间存在固定的线性关系
编写一个“好”的程序之前,必须分析待处理问题中各个对象的特性,以及对象之间的关系。
基本概念总结:
1.1.4数据的逻辑结构
指数据元素之间的逻辑关系。
即从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。
逻辑结构可细分为4类:
1.1.5数据的物理结构
1.1.6数据的运算
1.2、算法
1.2.1算法概念
算法是特定问题求解步骤的描述
在计算机中表现为指令的有限序列
算法是独立存在的一种解决问题的方法和思想。
对于算法而言,语言并不重要,重要的是思想。
1.2.2算法和数据结构区别
数据结构只是静态的描述了数据元素之间的关系
高效的程序需要在数据结构的基础上设计和选择算法
===程序=数据结构+算法
总结:
算法是为了解决实际问题而设计的
数据结构是算法需要处理的问题载体
数据结构与算法相辅相成
1.2.3算法特性
输入
算法具有0个或多个输入
输出
算法至少有1个或多个输出
有穷性
算法在有限的步骤之后会自动结束而不会无限循环
确定性
算法中的每一步都有确定的含义,不会出现二义性
可行性
算法的每一步都是可行的
1.2.4算法效率的度量
1、事后统计法
比较不同算法对同一组输入数据的运行处理时间
缺陷
为了获得不同算法的运行时间必须编写相应程序
运行时间严重依赖硬件以及运行时的环境因素
算法的测试数据的选取相当困难
事后统计法虽然直观,但是实施困难且缺陷多
算法效率的度量
事前分析估算
依据统计的方法对算法效率进行估算
影响算法效率的主要因素
算法采用的策略和方法
问题的输入规模
编译器所产生的代码
计算机执行速度
//算法最终编译成具体的计算机指令
//每一个指令,在具体的计算机上运行速度固定
//通过具体的n的步骤,就可以推导出算法的复杂度
longsum1(intn)
{
longret=0;
int*array=(int*)malloc(n*sizeof(int));
inti=0;
for(i=0;i { array[i]=i+1; } for(i=0;i { ret+=array[i]; } free(array); returnret; } longsum2(intn) { longret=0; inti=0; for(i=1;i<=n;i++) { ret+=i; } returnret; } longsum3(intn) { longret=0; if(n>0) { ret=(1+n)*n/2; } returnret; } intmain() { printf("%d\n",sum1(100)); printf("%d\n",sum2(100)); printf("%d\n",sum3(100)); return0; } intfunc(inta[],intlen) { inti=0; intj=0; ints=0; for(i=0;i { for(j=0;j { s+=i*j;//n*n } } returns; } //n*n 注意1: 判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略。 注意2: 在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度。 2、大O表示法 算法效率严重依赖于操作(Operation)数量 在判断时首先关注操作数量的最高次项 操作数量的估算可以作为时间复杂度的估算 O(5)=O (1) O(2n+1)=O(2n)=O(n) O(n2+n+1)=O(n2) O(3n3+1)=O(3n3)=O(n3) 常见时间复杂度 关系 3、算法的空间复杂度 算法的空间复杂度通过计算算法的存储空间实现 S(n)=O(f(n)) 其中,n为问题规模,f(n))为在问题规模为n时所占用存储空间的函数 大O表示法同样适用于算法的空间复杂度 当算法执行时所需要的空间是常数时,空间复杂度为O (1) 空间与时间的策略 多数情况下,算法执行时所用的时间更令人关注 如果有必要,可以通过增加空间复杂度来降低时间复杂度 同理,也可以通过增加时间复杂度来降低空间复杂度 练习1: 分析sum1sum2sum3函数的空间复杂度 O(4n+12)O(8)=O (1)O(4)=O (1) 总结: 实现算法时,需要分析具体问题,对执行时间和空间的要求。 练习2: 时间换空间 /* 问题: 在一个由自然数1-1000中某些数字所组成的数组中,每个数字可能出现零次或者多次。 设计一个算法,找出出现次数最多的数字。 */ 方法1: 排序,然后找出出现次数最多的数字 方法2: voidsearch(inta[],intlen) { intsp[1000]={0}; inti=0; intmax=0; for(i=0;i { intindex=a[i]-1; sp[index]++; } for(i=0;i<1000;i++) { if(max { max=sp[i]; } } for(i=0;i<1000;i++) { if(max==sp[i]) { printf("%d\n",i+1); } } } intmain() { intarray[]={1,1,3,4,5,6,6,6,2,3}; search(array,sizeof(array)/sizeof(*array)); return0; } 把每个数字出现的次数的中间结果,缓存下来;在缓存的结果中求最大值。 2、线性表 2.1线性表基本概念 2.1.1线性表定义 线性表(List)是零个或多个数据元素的集合 线性表中的数据元素之间是有顺序的 线性表中的数据元素个数是有限的 线性表中的数据元素的类型必须相同 2.1.2数学定义 线性表是具有相同类型的n(≥0)个数据元素的有限序列 (a1,a2,…,an) ai是表项,n是表长度。 2.1.3性质 a0为线性表的第一个元素,只有一个后继 an为线性表的最后一个元素,只有一个前驱 除a0和an外的其它元素ai,既有前驱,又有后继 线性表能够逐项访问和顺序存取 2.1.4练习 下面的关系中可以用线性表描述的是 A.班级中同学的友谊关系N: N B.公司中的上下级关系1: N C.冬天图书馆排队占座关系 D.花名册上名字之间的关系1: : 1 2.2.5线性表的操作 创建线性表 销毁线性表 清空线性表 将元素插入线性表 将元素从线性表中删除 获取线性表中某个位置的元素 获取线性表的长度 线性表在程序中表现为一种特殊的数据类型 线性表的操作在程序中的表现为一组函数 C语言描述=====》线性表的设计与实现 ADT抽象层《[数据结构(C语言版)].严蔚敏_吴伟民.扫描版.pdf》p44页 人生财富库积累 #ifndef_WBM_LIST_H_ #define_WBM_LIST_H_ typedefvoidList; typedefvoidListNode; //创建并且返回一个空的线性表 List*List_Create(); //销毁一个线性表list voidList_Destroy(List*list); //将一个线性表list中的所有元素清空,线性表回到创建时的初始状态 voidList_Clear(List*list); //返回一个线性表list中的所有元素个数 intList_Length(List*list); //向一个线性表list的pos位置处插入新元素node intList_Insert(List*list,ListNode*node,intpos); //获取一个线性表list的pos位置处的元素 ListNode*List_Get(List*list,intpos); //删除一个线性表list的pos位置处的元素返回值为被删除的元素,NULL表示删除失败 ListNode*List_Delete(List*list,intpos); #endif 注意: intList_Insert(List*list,ListNode*node,intpos);(重点: 分离思想) 2.2线性表的顺序存储结构 2.2.1基本概念 2.2.2设计与实现 插入元素算法 判断线性表是否合法 判断插入位置是否合法 把最后一个元素到插入位置的元素后移一个位置 将新元素插入 线性表长度加1 获取元素操作 判断线性表是否合法 判断位置是否合法 直接通过数组下标的方式获取元素 删除元素算法 判断线性表是否合法 判断删除位置是否合法 将元素取出 将删除位置后的元素分别向前移动一个位置 线性表长度减1 链表顺序存储插入算法和删除算法 2.2.3优点和缺点 优点: 无需为线性表中的逻辑关系增加额外的空间 可以快速的获取表中合法位置的元素 缺点: 插入和删除操作需要移动大量元素 当线性表长度变化较大时难以确定存储空间的容量 2.3线性表的链式存储 2.3.1基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息。 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息 尾结点 链表中的最后一个数据结点,其下一元素指针为空,表示无后继。 2.3.2链表技术领域推演 2.3.2设计与实现 链表链式存储_api实现分析 在C语言中可以用结构体来定义链表中的指针域 链表中的表头结点也可以用结构体实现 带头结点、位置从0的单链表 返回链表中第3个位置处,元素的值 LinkListNode*LinkList_Get(LinkList*list,intpos) { inti=0; TLinkList*tList=(TLinkList*)list; LinkListNode*current=NULL; LinkListNode*ret=NULL; if(list==NULL||pos<0||pos>=tList->length) { returnNULL; } current=(LinkListNode*)tList; for(i=0;i { current=current->next; } ret=current->next; returnret; } 返回第三个位置的 移动pos次以后,当前指针指向哪里? 答案: 指向位置2,所以需要返回ret=current->next; 备注: 循环遍历时,遍历第1次,指向位置0 遍历第2次,指向位置1 遍历第3次,指向位置2 遍历第n次,指向位置n-1; 所以如果想返回位置n的元素的值,需要怎么做 ret=current->next; 此问题是: 指向头结点的指针移动n次和第n个元素之间的关系? 删除元素 重要技术场景图 链表链式存储_插入 链表链式存储_删除 2.3.3优点和缺点 优点: 无需一次性定制链表的容量 插入和删除操作无需移动数据元素 缺点: 数据元素必须保存后继元素的位置信息 获取指定数据的元素操作需要顺序访问之前的元素 2.4循环链表 2.4.1基本概念 循环链表的定义: 将单链表中最后一个数据元素的next指针指向第一个元素 循环链表拥有单链表的所有操作 创建链表 销毁链表 获取链表长度 清空链表 获取第pos个元素操作 插入元素到位置pos 删除位置pos处的元素 新增功能: 游标的定义 在循环链表中可以定义一个“当前”指针,这个指针通常称为游标,可以通过这个游标来遍历链表中的所有元素。 循环链表新操作 将游标重置指向链表中的第一个数据元素 CircleListNode*CircleList_Reset(CircleList*list); 获取当前游标指向的数据元素 CircleListNode*CircleList_Current(CircleList*list); 将游标移动指向到链表中的下一个数据元素 CircleListNode*CircleList_Next(CircleList*list); 直接指定删除链表中的某个数据元素 CircleListNode*CircleList_DeleteNode(CircleList*list,CircleListNode*node); //根据元素的值删除元素pk根据元素的位置删除元素 2.4.2循环链表的应用 2.4.2.1证明循环链表 打印两次。 2.4.2.2约瑟夫问题求解 约瑟夫问题-循环链表典型应用 n个人围成一个圆圈,首先第1个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列。 然后再从下一个人开始从1顺时针报数,报到第m个人,再令其出列,…,如此下去,求出列顺序。 大话数据结构3.16结尾: 写书的人,也很累;临界点 2.4.3设计与实现 2.4.3.1循环链表插入元素的分析 1)普通插入元素(和单链表是一样的) 2)尾插法(和单链表是一样的,单链表的写法支持尾插法; 因: 辅助指针向后跳length次,指向最后面那个元素) CircleList_Insert(list,(CircleListNode*)&v1,CircleList_Length(list)); CircleList_Insert(list,(CircleListNode*)&v1,CircleList_Length(list)); 3)头插法(要进行头插法,需要求出尾结点,和单链表不一样的地方,保证是循环链表) 第一次插入元素时,让游标指向0号结点 CircleList_Insert(list,(CircleListNode*)&v1,0); CircleList_Insert(list,(CircleListNode*)&v1,0); 4)第一次插入元素 2.4.3.2循环链表插入综合场景分析图 2.4.3.3循环链表删除结点分析 1、删除普通结点 2、删除头结点(删除0号位置处元素),需要求出尾结点 2.4.4优点和缺点 优点: 功能强了。 循环链表只是在单链表的基础上做了一个加强 循环链表可以完全取代单链表的使用 循环链表的Next和Current操作可以高效的遍历链表中的所有元素 缺点: 代码复杂度提高了 大话数据结构3.16结尾: 写书的人,也很累;临界点 2.5双向链表 2.5.1基本概念 请思考: 为什么需要双向链表? 单链表的结点都只有一个指向下一个结点的指针 单链表的数据元素无法直接访问其前驱元素 逆序访问单链表中的元素是极其耗时的操作! len=LinkList_Length(list); for(i=len-1;len>=0;i++)//O(n) { LinkListNode*p=LinkList_Get(list,i);//O(n) //访问数据元素p中的元素 // } 双向链表的定义 在单链表的结点中增加一个指向其前驱的pre指针 双向链表拥有单链表的所有操作 创建链表 销毁链表 获取链表长度 清空链表 获取第pos个元素操作 插入元素到位置pos 删除位置pos处的元素 2.5.2设计与实现 循环链表一般操作 插入操作 插入操作异常处理 插入第一个元素异常处理 在0号位置处插入元素; 删除操作 删除操作异常处理 双向链表的新操作 获取当前游标指向的数据元素 将游标重置指向链表中的第一个数据元素 将游标移动指向到链表中的下一个数据元素 将游标移动指向到链表中的上一个数据元素 直接指定删除链表中的某个数据元素 DLinkListNode*DLinkList_DeleteNode(DLinkList*list,DLinkListNode*node); DLinkListNode*DLinkList_Reset(DLinkList*list); DLinkListNode*DLinkList_Current(DLinkList*list); DLinkListNode*DLinkList_Next(DLinkList*list); DLinkListNode*DLinkList_Pre(DLinkList*list); //大家一定要注意: 教科书不会告诉你项目上如何用;哪些点是项目的重点; 做一个企业级的财富库,完成你人生开发经验的积累,是我们的学习重点,要注意! 双向链表重要技术场景 循环链表插入结点技术场景 循环链表删除结点技术场景 2.5.3优点和缺点 优点: 双向链表在单链表的基础上增加了指向前驱的指针 功能上双向链表可以完全取代单链表的使用 双向链表的Next,Pre和Current操作可以高效的遍历链表中的所有元素 缺点: 代码复杂 3、栈tack和队列queue 3.1栈stack 3.1.1Stack基本概念 栈是一种特殊的线性表 栈仅能在线性表的一端进行操作 栈顶(Top): 允许操作的一端 栈底(Bottom): 不允许操作的一端 3.1.2Stack的常用操作 创建栈 销毁栈 清空栈 进栈 出栈 获取栈顶元素 获取栈的大小 C语言描述=====》栈的设计与实现人生财富库积累 #ifndef_MY_STACK_H_ #define_MY_STACK_H_ typedefvoidStack; Stack*Stack_Create(); voidStack_Destroy(Stack*stack); voidStack_Clear(Stack*stack); intStack_Push(Stack*stack,void*item); void*Stack_Pop(Stack*stack); void*Stack_Top(Stack*stack); intStack_Size(Stack*stack); #endif//_MY_STACK_H_ 3.1.3栈模型和链表模型关系分析 3.1.4栈的顺序存储设计与实现 基本概念 设计与实现 头文件 #ifndef__MY_SEQLIST_H__ #define__MY_SEQLIST_H__ typedefvoidSeqList; typedefvoidSeqListNode; SeqList*SeqStack_Create(intcapacity); voidSeqStack_Destroy(SeqStack*list); voidSeqStack_Clear(SeqStack*list); intSeqStack_Length(SeqStack*list); intSeqStack_Capacity(SeqStack*list); intSeqStack_Insert(SeqStack*list,SeqListNode*node,intpos); SeqListNode*SeqList_Get(SeqList*list,intpos); SeqListNode*SeqList_Delete(SeqList*list,intpos); #endif//__M
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 传智播客 C+ 数据结构 基础 讲义