传智播客C和C++与数据结构基础讲义.docx

上传人:b****5 文档编号:8272004 上传时间:2023-01-30 格式:DOCX 页数:77 大小:6.16MB
下载 相关 举报
传智播客C和C++与数据结构基础讲义.docx_第1页
第1页 / 共77页
传智播客C和C++与数据结构基础讲义.docx_第2页
第2页 / 共77页
传智播客C和C++与数据结构基础讲义.docx_第3页
第3页 / 共77页
传智播客C和C++与数据结构基础讲义.docx_第4页
第4页 / 共77页
传智播客C和C++与数据结构基础讲义.docx_第5页
第5页 / 共77页
点击查看更多>>
下载资源
资源描述

传智播客C和C++与数据结构基础讲义.docx

《传智播客C和C++与数据结构基础讲义.docx》由会员分享,可在线阅读,更多相关《传智播客C和C++与数据结构基础讲义.docx(77页珍藏版)》请在冰豆网上搜索。

传智播客C和C++与数据结构基础讲义.docx

传智播客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模板 > 动态背景

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1