数据结构初阶 —— 概述

目录

一,数据结构(Data Structure)

数据结构

数据的逻辑结构

数据的存储结构(物理结构)

八类常见数据结构

 二,算法(Algorithm)

算法特征

数据对象的运算和操作

算法要求

算法效率

时间复杂度

空间复杂度

方法

案例

1,冒泡排序

2,二分查找

3,阶乘递归

4,斐波那契递归


数据结构 + 算法 = 程序

一,数据结构(Data Structure)

数据结构

  • 计算机存储、组织数据的方式;
  • 指相互之间存在一种或多种特定关系的数据元素的集合;
  • 可用来高效运行和存储,往往与检索算法和索引技术有关;

数据的逻辑结构

  • 集合:数据结构中的元素之间“同属一个集合” 的相互关系,但元素之间相互孤立; 
  • 线性结构:数据结构中的元素存在一对一的相互关系; 
  • 树形结构:数据结构中的元素存在一对多的相互关系;
  • 图形结构数据结构中的元素存在多对多的相互关系;

按逻辑简单分类

  • 线性结构,栈、队列和串等;
  • 非线性结构,数组、广义表、树结构和图结构等;

数据的存储结构(物理结构)

  • 在计算机存储空间中的存放形式;
  • 顺序存储、链式存储、索引存储和哈希存储等;

八类常见数据结构

  • 数组(Array)

  • 栈(Stack)

  • 队列(Queue)

  • 链表(Linked List)

  • 树(Tree)

  • 图(Graph)

  • 堆(Heap)

  • 散列表(Hash)

数据结构初阶 —— 概述_第1张图片

 二,算法(Algorithm)

  • 对特定问题求解步骤的一种描述,它是指令的特定序列,每一条指令表示一个或多个操作;

算法特征

  • 有穷性(Finiteness),指算法必须能在执行有限个步骤之后终止;
  • 确切性(Definiteness),算法的每一步骤必须有确切的定义;
  • 可行性(Effectiveness)执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性);
  • 输入项(Input),一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
  • 输出项(Output),一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;

数据对象的运算和操作

  • 算术运算:加减乘除等运算;
  • 逻辑运算:或、且、非等运算;
  • 关系运算:大于、小于、等于、不等于等运算;
  • 数据传输:输入、输出、赋值等运算;

算法要求

  • 正确性
  • 可读性
  • 健壮性
  • 简单性
  • 时间效率高而且空间使用率低

算法效率

  • 同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率;
  • 衡量一个算法的好坏,时间复杂度和空间复杂度;
//问题规模N
void Func1(int N)
{
	int count = 0;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < N; ++j)
		{
			++count;
		}
	}

	for (int k = 0; k < 2 * N; ++k)
	{
		++count;
	}

	int M = 10;
	while (M--)
	{
		++count;
	}
	printf("%d\n", count);
}

以上Func1 执行的基本操作次数:

        F(N)=N^2+2*N+10

时间复杂度

  • 计算基本运算的执行次数,t(n) = O(f(n)),表示随问题规模n增大,算法执行时间的增长率和f(n)的增长率正相关;
  • 实际中只需计算大概的执行次数,即大O渐进表示法;

 大O渐进表示法(即去掉了那些对结果影响不大的项

  • 用常数1取代运行时间中的所有加法常数;
  • 在修改后的运行次数函数中,只保留最高阶项;
  • 如果最高阶项存在且不是1,则去除与这个项相乘的常数;

使用大O的渐进表示法,Func1的时间复杂度为:

        O(N^2)

 注:另外有些算法的时间复杂度存在最好、平均和最坏情况,在实际中一般情况关注的是算法的最坏运行情况;

常数阶:O(1)

  • 基本运算次数与问题规模无关;
  • O(1)不代表1次运算;

常用的算法时间复杂度的关系:

  • O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(2^n) < O(n!

空间复杂度

  • 算法在运行过程中临时占用的空间的度量,一般也是问题规模n的函数s(n) = O(g(n));
  • 函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定
  • 空间复杂度不是程序占用了多少空间,算的是变量的个数; 空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
  • 算法的时间复杂度和空间复杂度相互影响,好的时间复杂度也可能会占用较多的存储空间;

数据结构初阶 —— 概述_第2张图片

数据结构初阶 —— 概述_第3张图片

方法

  • 递推法

  • 递归法

  • 穷举法(暴力破解法)

  • 贪心算法

  • 分治法

  • 动态规划法

  • 迭代法

  • 分支界限法

  • 回溯法

案例

1,冒泡排序

时间复杂度

  • 最好O(N),平均O(N^2),最差O(N^2); 
  • N+(N-1)+(N-2)+...+1

空间复杂度

  • 使用了常数个额外空间,O(1);
//冒泡排序
void BubbleSort(int* parr, int sz)
{
	assert(parr);
	int i = 0;
	for (i; i < sz - 1; i++)
	{
		int j = 0;
		int flag = 0;
		for (j; j < sz - 1 - i; j++)
		{
			if (parr[j] > parr[j + 1])
			{
				int tmp = parr[j];
				parr[j] = parr[j + 1];
				parr[j + 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0)
			break;
	}
}

2,二分查找

时间复杂度

  • 最好O(1),最差O(logN); 
  • 1 = N/2^x 

空间复杂度

  • 使用了常数个额外空间,O(1);
//二分查找
int BinarySearch(int* a, int n, int x)
{
	assert(a);
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mid = begin + ((end - begin) >> 1);
		if (a[mid] < x)
			begin = mid + 1;
		else if (a[mid] > x)
			end = mid;
		else
			return mid;
	}
	return -1;
}

数据结构初阶 —— 概述_第4张图片

3,阶乘递归

时间复杂度

  • O(N) ;
  • 时间复杂度 = 递归次数的累加;

空间复杂度

  • O(N);
long long Fac(size_t N)
{
 if(1 == N)
 return 1;

 return Fac(N-1)*N;
}

4,斐波那契递归

时间复杂度

  • O(2^N) ;
  • 2^0+2^1+2^2+...+2^(n-3)+2^(n-2) = 2^(n-1)-1

空间复杂度

  • O(N)
long long Fib(size_t N)
{
 if(N < 3)
 return 1;

 return Fib(N-1) + Fib(N-2);
}

数据结构初阶 —— 概述_第5张图片

你可能感兴趣的:(编程语言,数据结构,数据结构,算法)