数据结构之整体概述和预备知识
一、概述
我们通常会把现实中大量而复杂的问题以特定的数据类型和特定的存储结构存放到主存储器中,以及在此基础上为实现某个功能(比如查找某个元素、删除某个元素、对元素进行排序等)而执行相应的操作,这个相应的操作也叫算法。
(1)数据结构
狭义上,数据结构是研究数据存储结构的一门学科;广义上,数据结构还包含了对算法的研究。
数据结构是软件核心课程,但是学完不一定立刻见效,但对日后理解程序等有莫大帮助。
(2)算法:
狭义上,算法与数据的存储密切相关,即不同数据结构就算同一类型排序方法写出来的程序也不一定相同;广义上,算法与数据的存储无关,即排序就是一种算法,管你是什么数据结构,排序算法大体思路都一样。
衡量算法先进的标准
- 时间复杂度:程序大概要执行的次数,而非时间,比如不同电脑性能不同,相同程序执行的时间也就不一样。
有关时间复杂度的补充:
(1)我们常用大写O()来体现时间复杂度的记法,我们称之为大O记法。
(2)推导大O阶的方法
1. 用常数1取代运行时间中的所有加法常数;
2. 在修改后的运行次数函数中,只保留最高阶项;
3. 如果最高阶存在且其系数不是1,则去除与这个项相乘的系数,得到的结果就是大O阶。
(3)举例说明:
1. 常数阶
int sum=0,n=100; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; sum=(1+n)*n/2; printf("%d",sum);
尽管总共执行了13次,但n都是确定的,遵从方法一原则,所以时间复杂度为O(1);
2. 线性阶
int i; for(i=0;i<n;i++) { /*O(1)的程序步骤集合*/ }
去除常数项,很明显时间复杂度就为O(n);
3. 平方阶
int i,j; for(i=0;ii<n;i++) for(j=i;j<n;j++) { O(1); } }
根据数列求和可知总执行数为:(n^2)/2+n/2,只保留最高项且去除最高项系数,故时间复杂度为O(n^2).
(4)常用的时间复杂度所消耗的时间从小到大依次是
O(1)<O(log n)<O(n)<O(nlog n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)
实际情况中,当n很大时,n^3及以后的不做讨论要求。
(5)最坏运行情况
比如在房间里找个东西,最好能立刻找到,最坏得把房间里所有搜索完才可以找到,这中最坏情况就是最坏运行情况。
- 空间复杂度:程序执行过程中大概所占用的最大内存空间
- 难易程度:别人能不能看的懂
- 健壮性:是否容易受到bug的干扰。
二、预备知识
指针知识补充:
- 地址是从零开始的非负整数
- 指针的本质是一个受限的非负整数,不能进行乘除等操作,加减可以。
- 指针变量定义之后为野指针,即所指向的地址不明确。
- 指针变量在32位系统下只占用4个字节
- 对于任何一变量而言,其第一个字节首地址就是该变量的地址。
结构体知识补充:
- 结构体变量不能加减乘除,但同类型之间可以相互赋值
- 结构体变量通常有很多成员,内存很大,函数传参最好传送结构体变量首地址为好。
动态分配内存:
- 如果开拓了某内存区域之后,该区域不用了,需要用free(*)将其释放出去,否则会造成内存泄漏问题
- 函数形参实参传递过程中,当函数调用完毕之后,形参就会给释放,我们通常都传递或者返回指针
- 程序中往往要判断内存是否动态分配成功。
typedef的使用
优点:代替长名字,方便输入,定义的名字通常使用大小写。
例:
typedef struct Student { int sidl char name[100]; char sex; }*PST //PST等价于struct Student *
三、数据结构整体框架
数据结构可以归纳为如下两类:
- 线性结构:该结构的数据元素之间存在一对一的关系。典型:数组、链表。合理应用数组、链表可得栈、队列
- 非线性结构:该结构的数据元素之间存在一对多或多对多关系。典型:树、图。

浙公网安备 33010602011771号