数据结构与算法 - 基础

本文首发于 个人博客

程序 = 数据结构 + 算法

其实很多同学知道数据结构与算法很重要,但是却不明觉厉。 这里我们看一个简单的题:

对自然数从1到100的求和

最简单的设计无非是:

void addNum () 
{    
  int total = 0;    
  for (int i = 1; i <= 100; i ++) {     
     total += i;  
  }   
 printf("total is %d \n",total);// 5050}

没毛病,但是哥根廷的数学家 高斯 在其9岁的时候就发明了一个快速计算等差数列求和的小技巧 (1+100,2+99,3+98.....),总共50 对101,结果5050。其公式可以归纳为:

不论n多大,我们只用算一次就可以得出结果,而上面的循环却要循环n次,n很小无所谓,如果几万几十万这个时间消耗不言而喻,由此可见数据结构与算法确实很重要。

数据

数据结构中最基本的5个概念:数据、数据元素、数据项、数据对象,他们整体构成数据结构。

image

比较抽象,我们用代码来展示如下:

struct Teacher {
    char *name;
    char *sex;
    int age;
};

int main(int argc, const char * argv[]) {
    struct Teacher t1;          // 数据元素
    struct Teacher tArray[10];  // 数据对象( 一组数据元素组成 )
    t1.name = "Mary";           // 数据项
    t1.sex = "female";          // 数据项
    t1.age = 23;                // 数据项
    return 0;
}

数据元素之间不是独立的,存在特定的关系,这些关系即结构,数据结构指的就是数据对象中数据元素之间的关系。

结构

从视角的不同作以区分,我们将数据结构分为两种类型:逻辑结构物理结构

逻辑结构

逻辑结构分为:集合结构线性结构树形结构图形结构

  • 集合结构

集合结构中的数据元素除了同属一个集合外,彼此之间没有其他关系。

  • 线性结构

线性结构中的数据元素之间都是一对一的关系,从图中也可以看出他们像一条线一样把各个元素连起来,常用的线性结构有:链表队列数组 等等。

  • 树形结构
树状.jpg

树形结构中的元素是呈现一对多的关系,常见的树有:二叉树B树哈夫曼树 等等。

  • 图形结构

图形结构之间的元素是多对多的关系,常见的图形结构有: 矩阵 等。

物理结构

物理结构其实就是存储结构,就是存储到计算机中的形式。数据存储的结构才真正反映了数据存在的样式,也反映了数据元素之间的逻辑关系,如何设计数据的存储以及相互之间的关系才是数据结构的关键。

  • 顺序存储

我们知道计算机中的内存都是连续的,如上图所述,1-6个元素按照顺序存储的方式存到内存里,比如第一个元素的内存地址是 0x000001 假设我们这个顺序表中每个元素占1个位置,那么很容易得到第二个元素的地址是 0x000002,以此类推很容易知道第六个元素的地址是 0x000006

  • 链式存储

这里我画了一个简单的图,大概描述了一下链式存储在内存中是如何体现的。当我们的元素在内存中是散乱的,也就是他们的地址之间没有一定的规律,这个时候就要靠我们的指针去标记位置了,比如我们把 元素2 的物理地址 0x000019 存储到 元素1 中去,那么每两个元素之间就会有一定的相互绑定的关系,这就是链式存储的基本逻辑。

通过上述我们会发现,顺序存储的结构查找会很容易,因为直接按照顺序对应的索引就能对应找到相应的内存地址,而链式存储则不行,不过链式存储的结构对于数据的增删就特别快了,因为他们之间的关系靠的是指针,而不是内存地址的偏移。

算法

算法是解决特定问题步骤的描述,在计算机中表现为解决特定问题的一系列代码

数据结构脱离算法,或者算法脱离数据结构都是无法进行的,因为算法是基于数据结构进行的,只有数据结构而没有算法那么数据结构存在就没有意义了。

程序 = 数据结构 + 算法

算法的特性

  • 输入输出

  • 有穷性 :当然不能是无限循环了...

  • 确定性 : 每一步都是明确的,不能出现模棱两可选择。

  • 可行性

算法的设计要求

  • 正确性

  • 可读性

  • 健壮性

  • 时间效率高和存储量低 :其实这才是算法的精髓,研究算法无非就是要提高效率和降低存储。

时间空间复杂度

通常我们用程序代码执行的次数作为算法时间复杂度的衡量,通常我们用 大O 法来进行标记。

  • 用常数1取代运行时间中的所有常数

  • 各种复杂度相加,只保留最高阶 n+2n+log(n)+n^2 -----> n^2

  • 如果最高阶存在且不是1,则去掉这个项相乘的常数 O(5logn) -----> O(logn)

    常数阶

    通常用O(1) 来表示

//1+1+1 = 3
void testSum1(int n){
    int sum = 0;                //执行1次
    sum = (1+n)*n/2;            //执行1次
    printf("testSum2:%d\n",sum);//执行1次
}

不管n是多少,这个地方都只用执行1次,所以n不会影响其时间复杂度,O(1)

线性阶

void add2(int x,int n){
    for (int i = 0; i < n; i++) {
        x = x+1;
    }
}

可以发现这个for循环会执行n次,所以其时间复杂度为 O(n)

对数阶

int count = 1;
while(count < n){
    count = count * 2;
}

上述算法换个写法就是2^x = n 就可以得到 x = log2n,我们说过常数如果不是1都可以去掉,最终结果就是 O(logn)

平方阶

// x=x+1; 执行n*n次
void add3(int x,int n){
    for (int i = 0; i< n; i++) {
        for (int j = 0; j < n ; j++) {
            x=x+1;
        }
    }
}

外层循环n次,内层循环n次,加在一起就是 n*n = n^2 次,所以其时间复杂度为 O(n^2)

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

其实我们只用关注前面的复杂度就行了,如果你的算法时间复杂度像后面的那几位靠齐,也就没啥好说的了,指数级的增长还是蛮恐怖的。

空间复杂度

算法设计有一个重要原则: 空间 时间 权衡

算法的空间负责度是通过计算算法所需的存储空间实现,算法空间复杂度的计算公式是:s(n) = n(f(n)) 其中n为问题的规模,f(n) 为语句关于n所占存储空间的函数。

我们通过一个简单的例子大概了解一下空间复杂度:

int n = 5;
    int a[10] = {1,2,3,4,5,6,7,8,9,10};

    //算法实现(1)
    /*
    算法(1),仅仅通过借助一个临时变量temp,与问题规模n大小无关,所以其空间复杂度为O(1);
    */
    int temp;
    for(int i = 0; i < n/2 ; i++){
        temp = a[i];
        a[i] = a[n-i-1];
        a[n-i-1] = temp;
    }

    for(int i = 0;i < 10;i++)
    {
        printf("%d\n",a[i]);

    }


    //算法实现(2)
    /*
     算法(2),借助一个大小为n的辅助数组b,所以其空间复杂度为O(n).
    */
    int b[10] = {0};
    for(int i = 0; i < n;i++){
        b[i] = a[n-i-1];
    }
    for(int i = 0; i < n; i++){
        a[i] = b[i];
    }
    for(int i = 0;i < 10;i++)
    {
        printf("%d\n",a[i]);

    }

需要注意的是:算法的空间复杂度并不是整个算法占用内存的空间,而是该算法在实现的时候所需的辅助空间。

研究算法的最终目的是要提高程序运行的效率,我们还想降低程序运行所占用的内存等等,这两个一个是时间维度,一个是空间唯独。一个好的算法并不是说一定要时间复杂度低,也不一定要空间占用小,这些东西要根据项目实际情况去均衡。希望这篇文章能够将数据结构与算法的基础知识讲清楚。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 数据 元素又称为元素、结点、记录是数据的基本单位 数据项是具有独立含义的最小标识单位 数据的逻辑结构 数据的逻辑结...
    PPPeg阅读 13,684评论 0 15
  • 数据 元素又称为元素、结点、记录是数据的基本单位 数据项是具有独立含义的最小标识单位 数据的逻辑结构 数据的逻辑结...
    蒲熠星F1阅读 1,025评论 0 0
  • 一: 算法 算法:是一组有穷指令集,是解题方案的准确而完整的描述。通俗地说,算法就是计算机解题的过程。算法不等于程...
    CONLYOUC阅读 2,941评论 1 12
  • 1 数据结构基本概念和术语 说到数据结构,就要先了解数据。俗语云:“巧妇难为无米之炊”,再强大的计算机,也是要有“...
    RN_b780阅读 712评论 0 3
  • 前言 数据结构:是指相互之间存在一种或多种特定关系的数据元素的集合用计算机存储、组织数据的方式。数据结构分别为逻辑...
    SK_Wang阅读 507评论 0 4