一、内行看门道
数据结构要掌握的技能:编程思想和编程逻辑,用C语言根据编程逻辑去解决实际问题。
1、程序的本质?
2、为什么会有各种各样的程序?
程序是为了实际问题而存在,从本质上而言,程序是解决问题的步骤描述。所以为了解决实际生活中的各种问题,也就有了各种各样的程序。
下面是程序本质的一个张图:
既然程序的本质是要解决实际问题,那么,首先要考虑一下实际问题。只有你深入的分析实际的问题,然后才会编写出实际问题的解决步骤-程序。
1、确认问题类型
如:数值计算,求最小值个数
2、确认求解的步骤
如:打开文件,读数据,关闭文件,计算和
那么如何判断求解问题的好坏?
1、用尽量少的内存空间解决问题
2、用尽量少的步骤解决问题
一个优秀的开发者需要追求代码的高“性价比”!
1、程序是为具体问题而存在的
2、程序需要围绕问题的解决进行设计
3、同一个问题可以有多种解决方案
二、数据的艺术
1、数据结构的起源
1.1、计算机从解决数值计算问题到解决生活中的问题
1.2、现实生活中的问题涉及不同个体间的复杂联系
1.3、需要在计算机程序中描述生活中的个体间的联系
数据结构就是主要研究非数值计算程序问题中的操作对象以及它们之间的关系。
数据-程序的操作对象,用于描述客观事物
数据的特点:
1、可以输入到计算机
2、可以被计算机程序处理
数据是一个抽象的概念,将其进行分类后得到程序设计语言中的类型。如:int,float, char等等。
1、数据元素之间不是独立的,存在特定的关系,这些关系即结构
2、数据结构指数据对象中数据元素之间的关系
如:数组中各个元素之间存在固定的线性关系
编写一个“好”的程序之前,必须分析待处理问题中各个对象的特性,以及对象之间的关系。
逻辑结构:
集合结构:数据元素之间没有特别的关系,仅同属相同集合。
线性结构:数据元素之间是一对一的关系
树形结构:数据元素之间是一对多的层次关系
图形结构:数据元素之间是多对多的关系(腾讯的朋友圈,魔兽的地图)
物理结构:逻辑结构在计算机中的存储形式
顺序存储结构:将数据存储在地址连续的存储单元里
链式存储结构:将数据存储在任意的存储单元里,通过保存地址的方式找到相关联的数据元素
数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
按照视点的不同,数据结构可以分为逻辑结构和物理结构
三、程序的灵魂-算法
1、程序是否越短越好?
2、是否别人看不懂就证明自己很厉害?
数据结构与算法
1、数据结构只是静态的描述了数据元素之间的关系
2、高效的程序需要在数据结构的基础上设计和选择算法
高效的程序=恰当的数据结构+合适的算法
算法的定义
1、算法是特定问题求解步骤的描述
2、在计算机中表现为指令的有限序列
算法是独立存在的一种解决问题的方法和思想。
算法的特性:
输入:算法具有0个或多个输入
输出:算法至少有1个或多个输出
有穷性:算法在有限的步骤之后会自动结束而不会无限循环(这也是有别于程序的重要部分,如QQ程序在无人参与下,就是一个无穷程序)
确定性:算法的每一步都是有确定含义的,不会出现二义性。
可行性:算法的每一步都是可行的。
算法设计的准则:
正确性:
1、算法对于合法数据能够得到满足要求的结果
2、算法能够处理非法输入,并得到合理的结果
3、算法对于边界数据和压力数据都能得到满足要求的结果
主意:正确性是算法最需要满足的基本的准则,但是作为计算机程序,不可能无限制的满足这条准则。
算法设计的准则:
可读性:算法要方便阅读,理解和交流
健壮性:算法不应该产生莫名其妙的结果
高性价比:利用最少的时间和资源得到满足要求的结果
注意:算法的可读性是最容易忽略的,然而,程序是写给人看的,而不是计算机。
1、算法是为了解决实际问题而设计的
2、数据结构是算法需要处理的问题载体
3、数据结构与算法相辅相成
四、审判程序的灵魂
算法效率的度量
1、事后统计法
比较不同算法对同一组输入数据的运行处理时间
2、缺陷:
2.1、为了获得不同算法的运行时间必须编写相应的程序
2.2、运行时间严重依赖硬件以及运行时的环境因素
2.3、算法的测试数据的选取相当困难
事后统计法虽然直观,但是实施困难且缺陷多,一般不予考虑。
事前分析法:根据统计的方法对算法效率进行估算
影响算法效率的主要因素:1、算法采用的策略和方法2、问题的输入规模3、编译器所产生的代码4、计算机执行速度
算法效率的简单估算:
三种求和算法中求和的关键部分的操作数量为2n,n和1
随着问题规模n的增大,它们操作数量的差异会越来越大,因此实际算法的时间效率上的差异也会变得非常明显!
判断一个算法的效率往往只需要关注操作数量的最高次项,其它次要项和常熟项可以忽略。
算法效率的度量:
大O表示法:
1、算法效率严重依赖于操作数量
2、在判断时首先关注操作数量的最高次项
3、操作数量的估算可以作为时间复杂度的估算
O(5) = O(1)
O(2n + 1) = O(2n) = O(n)
O(n^2+n+1) = O(n^2)
O(3n^3+1) = O(3n^3) = O(n^3)
常见时间复杂度类型:
关系:
O(1)<O(logn)<O(n)<O(nlogn)<(n^2)<(n^3)<O(2^n)<O(n!)<O(n^n)
当算法在最坏情况下仍然能满足需求时,可以推断,算法的最好情况和平均情况都满足需求。
没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度。
算法的空间复杂度
1、算法的空间复杂度通过计算算法的存储空间实现
S(n) = O(f(n))
其中,n为问题规模,f(n)为在问题规模为n时所占用存储空间函数。
大O表示法同样适用于算法的空间复杂度,当算法执行时所需要的空间是常数时,空间复杂度为O(1)
空间与时间的策略
1、多数情况下,算法执行时所用的时间更令人关注
2、如果有必要,可以通过增加空间复杂度来降低时间复杂度
3、同理也可以通过增加时间复杂度来降低空间复杂度
在实现算法时,需要分析具体问题对执行时间和空间的要求。
空间换时间:
#include <stdio.h> /* 问题: 在一个由自然数1-1000中某些数字所组成的数组中,每个数字可能出现零次或者多次。 设计一个算法,找出出现次数最多的数字。 */ void search(int a[], int len) { int sp[1000] = {0}; int i = 0; int max = 0; for(i=0; i<len; i++) { int index = a[i] - 1; sp[index]++; } for(i=0; i<1000; i++) { if( max < sp[i] ) { max = sp[i]; } } for(i=0; i<1000; i++) { if( max == sp[i] ) { printf("%d\n", i+1); } } } int main() { int array[] = {1, 1, 3, 4, 5, 6, 6, 6, 2, 3}; search(array, sizeof(array)/sizeof(*array)); return 0; }
原文:http://blog.csdn.net/renren900207/article/details/20564003