精华内容
下载资源
问答
  • 2020-06-23 22:12:27

    时间复杂度

    • 对于算法时间复杂度的分析需要牢记一句话:将算法中基本操作的执行次数作为算法时间复杂度的度量。时间复杂度并不是执行完一段程序的总时间,而是其中基本操作的总次数。
    • 在考试的算法题目中你总能找到一个n,称为问题的规模。如你要处理的数组元素的个数为n,而基本操作所执行的次数是n的一个函数f(n)。对于求其基本操作执行的次数,就是求f(n)。求出以后就可以取出f(n)中随n增大而增大的最快的项,将其系数变为1,作为时间复杂度的度量。
      在这里插入图片描述

    计算时间复杂度的步骤

    1. 确定算法中的基本操作以及问题的规模
    2. 根据基本操作执行情况计算出规模n的函数f(n),并确定时间复杂度T(n)=O(f(n)中增长最快的项/此项的系数)在这里插入图片描述
    • 注意:一般将最坏的情况作为算法时间复杂度的度量
    例子1:
    void fun(int n)
    { 
        int  i = 1, j =100;
        while(i<n)
        {
            ++j;
            i+=2;
        }
    }
    解析:
    1.找出基本操作。
    显然++j;i+=2;都是基本操作
    2.确定规模
    确定n之后,可以看出循环是否结束和i有关,设循环m次后结束循环,此时i>n我们可得i最后的值为1+2m我们设1+2m+K=n(因为1+2m>n,所以加
    一个常数K来使他们想等从而求得m与n的关系,K是常数并不影响最终时间复杂度)得m=(n-1-K)/2,f(n)=(n-1-K)/2,其中增长最快的就是
    n/2,所以时间复杂度T(n)=O(n).
    
    例子2:
    void fun(int n)
    {
        int i,j,x=0;
        for(i=0;i<n;++i)
        {
        	for(j=i+1;j<n;++j)
        	{
        	++x;
        	}
        }
    }
    解析:
    1.找出基本操作
    ++x:处于最内层的循环,所以取++x;为基本操作。
    2.确定规模
    显然n为规模。
    下面列举i,j不同值情况下++x的执行次数
    i   j   ++x 
    0   1   n-1
    1   2   n-2
    ...........
    n-1 n    0
    利用等差数列求和的公式求出基本操作的执行次数:n(n-1)/2
    变化最快的项为n^2/2,因此时间复杂度为T(n) = O(n^2) 
    
    例子3:
    void funn(int n)
    {
    	int i=0,s=0;
    	while(s<n)
    	{
    		++i;
    		s+=i;
    	}
    }
    1.找出基本操作
    ++i和s+=i;都为基本操作
    2.确定规模
    显然n为规模
    设执行m次循环后结束,s1=1, s2=1+2, s3=1+2+3, ..., sm=m(m+1)/2(等差数列求和公式)
    求得m与n的关系,然后找出最高项将其系数变为1,得到T(n)=O(根号n)
    

    空间复杂度

    一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度,可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空间包括以下两部分。  
    (1)固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。
    (2)可变空间,这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。
    一个算法所需的存储空间用f(n)表示。S(n)=O(f(n))  其中n为问题的规模,S(n)表示空间复杂度。

    • 设计算法时,时间复杂度要比空间复杂度更容易出问题,所以一般情况一下我们只对时间复杂度进行研究。一般面试或者工作的时候没有特别说明的话,复杂度就是指时间复杂度。
    更多相关内容
  • 数据结构算法与应用:C++语言描述》不仅仅介绍了理论知识,还提供了50多个应用实例及600多道练习题。 该资源中就是其习题答案与代码。
  • 数据结构算法与应用:C++语言描述的书本及习题答案.zip ) 网络整理版
  • 数据结构算法设计题汇总

    千次阅读 2020-12-23 15:37:09
    typedef struct BSTNode {∥ 二叉排序树的结点结构 int data; ∥数据域 struct BSTNode *lchild, *rchild; ∥左、右孩子指针 }BSTNode,*BSTree; 设计递归算法,统计一棵二叉排序树T中值小于a的结点个数。 ...

    在这里插入图片描述
    在这里插入图片描述
    五、算法设计题(本题10分)
    34.二叉排序树的类型定义如下:
    typedef struct BSTNode {∥ 二叉排序树的结点结构
    int data; ∥数据域
    struct BSTNode *lchild, *rchild; ∥左、右孩子指针
    }BSTNode,*BSTree;
    设计递归算法,统计一棵二叉排序树T中值小于a的结点个数。

    在这里插入图片描述
    假设线性表采用顺序存储结构,其类型定义如下:
    #define ListSize 100
    typedef struct {
    int data[ListSize];
    int length;
    } SeqList, *Table;
    编写算法,将顺序表L中所有值为奇数的元素调整到表的前端。
    在这里插入图片描述
    在这里插入图片描述
    已知二叉树采用二叉链表存储,其结点结构定义如下:
    typedef struct Node{
    ElmType data;
    struct Node *lchild,*rchild;
    }*BiTree;
    在这里插入图片描述
    已知二叉树的定义如下:
    typedef struct node{
    int data;
    struct node *lchild, *rchild;
    }*Bitptr;
    编写递归算法求二叉树的高度。函数原型为:int f34(Bitptr t);

    在这里插入图片描述

    假设用带头结点的单循环链表表示线性表,单链表的类型定义如下:
    typedef struct node {
    int data;
    struct node*next;
    }LinkNode,*LinkList;
    编写程序,求头指针为head的单循环链表中data域值为正整数的结点个数占结点总数的比例,若为空表输出0,并给出所写算法的时间复杂度。函数原型为:
    float f34(LinkList head):

    在这里插入图片描述

    34.设顺序表L是一个递增有序表。编写算法,要求利用二分查找法确定插入位置,将
    元素x插入到L中,使L保持有序。
    在这里插入图片描述
    假设以单链表表示线性表,单链表的类型定义如下:
    typedef struct node {
    DataType data;
    Struct node next;
    } LinkNode,
    LinkList;
    编写算法,在一个头指针为head且带头结点的单链表中,删除所有结点数据域值为x的结点。函数原型为:LinkList delnode (LinkList head,DataType x)

    在这里插入图片描述
    二叉树的存储结构类型定义如下
    typedef struct node{
    int data;
    struct node *lchild, *rchild;
    } BinNode;
    typedef BinNode *BinTree;
    编写递归算法,求只有一个孩子结点的结点总数,并计算这些结点的数据值的和。
    函数的原型为:void f34(BinTree T, int *count, int *sum)
    count和sum的初值为0。
    在这里插入图片描述

    展开全文
  • java数据结构算法

    千人学习 2019-11-22 10:12:46
    做一门精致,全面详细的 java数据结构算法!!! 让天下没有难学的数据结构, 让天下没有难学的算法, 不吹不黑,我们的讲师及其敬业,可以看到课程视频,课件,代码的录制撰写,都是在深夜,如此用心,其心可鉴,他不掉头发,谁...
  • 数据结构算法的描述和分析

    千次阅读 2018-08-17 19:25:49
    数据结构概论 高级语言程序设计在解决某一实际问题的一般步骤是:分析实际问题、确定数学模型、设计或选择一个求解此数学模型的算法、编写程序进行调试和测试解决问题等几个步骤。 例1:已知:游泳池的长length和...

    数据结构概论

    高级语言程序设计在解决某一实际问题的一般步骤是:分析实际问题、确定数学模型、设计或选择一个求解此数学模型的算法、编写程序进行调试和测试解决问题等几个步骤。

    例1:已知:游泳池的长length和宽winde,求面积area。

    问题设计的对象有:游泳池的长length和宽wide,面积area;对象之间的关系(数学模型):A=L*W;

    程序:

    Main()

    {

    int len,wide,area;

    Scanf(“%d%d%\n”,&l,&w);

    Area=len*winde;

    Printf(“area=%d”,area);

    }

     

    解决游泳池面积或其他复杂的现实问题时,关键的不再是数学分析和计算方法,而是要设计出合适的数据结构,才能更有效有的解决生活的现实问题,著名的瑞士科学家沃思提出:程序设计=数据结构+算法      

    简单来说,数据结构是研究非数值的程序设计问题中计算机的操作对象以及它们之间的关系和操作的学科。

    具体来说,数据结构指的是数据之间的结构关系如何表示,如何存储,如何处理现实转化问题,即按某种关系组织起来的一组数据,再按一定的方式把它们存储在计算机的存储器中,并在这些数据上定义的一个运算的集合,称之为数据结构。

    基本概念和常用的术语

    数据:是客观事物的符号表示,在计算机科学中指所有能输入到计算机并能被计算机程序进行处理的符号总称。

    数据元素:是数据的基本单位。在计算机程序中通常作为一个整体考虑和处理。

    数据项:一个数据元素通常由若干个数据项组成,数据项是不可分割的最小单位。

    数据对象:是具有相同性质的数据元素的集合。

    数据结构是带有结构和操作的数据元素的集合。一般包含三个方面的内容。

    • 数据的逻辑结构

    在任何问题中,数据元素都不是孤立存在的,而是在它们之间存在着某种关系,这种数据元素相互之间的关系存在某种关系,这种数据元素是相互之间的关系称之为数据的逻辑结构。根据数据元素之间关系的不同特性,通常有下列四种基本结构形式。

    (1)集合:结构中的数据元素之间除了“同属于一个集合”的关系外,别无其他关系,元素之间为松散关系。

    (2)线性结构:结构中的数据元素存在一对一的关系,除第一个和最后一个元素外,其他每个元素都有且仅有一个直接前驱和一个直接后继。

    (3)树形结构:数据元素之间存在一对多的关系。一个数据元素可以与一个或多个元素存在关系,而且具有层次之分,其结构形式如倒立的生长的树。

    (4)图状结构或网状结构:数据元素之间存在多对多的关系,不存在层次关系。在这种关系中,数据元素之间不受任何限制。

    以上描述的4种关系是数据元素之间的逻辑关系,又称之为逻辑结构。

    • 数据的存储结构

    讨论数据逻辑结构的目的是为了在计算机中实现对它的操作,因此还要研究如何在计算机中表示它。

    数据元素在计算机中的存储(表示)方式称之为数据的物理结构,又称存储结构。它包含数据元素及数据元素之间关系的存储。是依赖于计算机语言的。

    在计算机内,数据的存储结构可以用一下四种基本存储方法实现

    (1)顺序存储结构:是将逻辑上相邻的元素节点存储在物理位置上也相邻的存储单元中,元素之间的逻辑关系由存储单元的邻接关系表示。由此得到的存储结构也称之为顺序结构。该结构通常用数组来实现。

    (2)链式存储结构:不要求逻辑上相邻的元素(节点)在物理位置上也相邻,而是在结点中借助指针域与该结点逻辑上相邻元素在内存中的地址来实现结点间的逻辑关系。由此得到的存储结构称为链式存储结构。及借助于引用或指针来表示数据元素之间的逻辑关系,被存放的元素被随机的存放在内存中再用指针将它们链接在一起。

    (3)索引存储结构:在存储元素信息的同时,还建立附加的索引表。

    (4)散列存储结构:根据元素的关键字直接计算出该元素的存储地址。

    三、数据的运算

    数据的运算,即对数据元素施加的操作,是定义在数据的逻辑结构上的,每种逻辑结构都有一个运算的集合。

    数据的运算地数据结构不可分割的一个方面,在给定了数据的逻辑结构和存储结构之后,按照定义的运算集合及运算性质的不同,可能导致完全不同的数据结构。

    另外,同一种逻辑结构,可以采用不同的存储结构。选择何种存储结构来表示相应的逻辑结构,要根据具体问题具体分析,主要考虑的还是数据运算方便及算法的时间和空间上的要求。

    算法的描述与分析

    算法描述

    算法:是对问题求解步骤的一种描述,是指令的有限序列。其中每条指令表示一个或多个操作。一个算法应具备以下5个特性:

    有限性:算法必须在有限的步骤之后结束

    确定性:算法的每一步都是确切的含义,无二义性。即在任何条件下,算法只有唯一的一条执行路径,即对于相同的输入只能得出相同的输出

    输入:一个算法可以接受零个或多个输入

    输出:一个算法至少有一个或多个输出

    可行性:算法中的每一步都可以通过已经实现的基本运算的有限次运行来实现

    算法分析

    求解一个问题可能有多种不同的算法,而算法的好坏直接影响程序的执行效率,且不同算法之间的运行效率相差巨大。

    设计一个“好”得算法应考虑达到算法应达到的四个目标:正确性、可读性、健壮性高效率与低存储量需求

    一个算法的评价可以从算法执行的时间与算法的所占用的内存空间两个方面来进行。

    算法的时间复杂度(time completexity)又称为计算复杂度,是算法有效性的度量之一。

    在解决实际问题的过程中不管是简单或复杂的算法,都必须是经过对应着一定的基本操作的次数。显然,如果一个算法中,运行基本操作的次数越少,那么它运行的时间也就相对越少,反之,如果次数越多,其运行的时间也就相对越多。所以,通常用它来衡量一个算法的运行时间性能或称之为计算性能。

    算法的空间复杂度(space completexity)是对一个算法在运行时占用存储空间大小的度量,也是衡量算法的有效性的一个重要的因素。因此,在分析一种算法的性能,不但需要分析算法的运行时间,还要分析算法所采用的的数据结构所占的空间。

    存储空间包括内存和外存,一般用字节作为空间的基本度量单位,问题的规模(或大小)为n,算法所需空间的空间单元数s一般是问题规模n的函数f(n)记作:S(n)=O(F(n))

     

    展开全文
  • 数据结构算法学习笔记

    万次阅读 多人点赞 2018-09-25 13:55:49
    本文是王争老师的《算法数据结构之美》的学习笔记,详细内容请看王争的专栏。有不懂的地方指出来,我做修改。 数据结构算法思维导图 数据结构指的是“一组数据的存储结构”,算法指的是“操作数据的一组...

    本文是王争老师的《算法与数据结构之美》的学习笔记,详细内容请看王争的专栏 。有不懂的地方指出来,我做修改。

    数据结构与算法思维导图

    数据结构指的是“一组数据的存储结构”,算法指的是“操作数据的一组方法”。
    数据结构是为算法服务的,算法是要作用再特定的数据结构上的。

    最常用的数据结构预算法:

    • 数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Tire树
    • 算法: 递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法

    1  算法的复杂度

    1.1大O复杂度表示法

     公式:

    T(n)表示代码执行的时间; n表示数据规模的大小; f(n) 表示每行代码执行的次数总和。因为这是一个公式, 所以用f(n)来表示。公式中的O,表示代码的执行时间T(n)与f(n)表达式成正比。

          所以,第一个例子中的T(n) = O(2n+2),第二个例子中的T(m) = 0(2n2 +2n+3)。这就是大O时间复杂度表示法。大O时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。

          当n很大时,你可以把它想象成10000、100000。 而公式中的低阶、常量、系数三部分并不左右增长趋势,所以都可以忽略。我们只需要记录一个最大量级就可以了,如果用大O表示法表示刚讲的那两段代码的时间复杂度,就可以记为: T(n) = O(n); T(n)= 0(n2)。
     

    1.2.复杂度分析法则

    1)单段代码看高频:比如循环。
    2)多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度。
    3)嵌套代码求乘积:比如递归、多重循环等
    4)多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加。

    1.3 时间复杂度分析

    • 只关注循环执行次数最多的一段代码
    • 加法法则:总复杂度等于量级最大的那段代码的复杂度
    • 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

    1.4 几种常见时间复杂度实例分析

    多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。包括,
    O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n^2)(平方阶)、O(n^3)(立方阶)
    非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。包括,
    O(2^n)(指数阶)、O(n!)(阶乘阶)

    • O(1) :

    常量级时间复杂度,只要代码的执行时间不随 n 的增大而增长,这样代码的时间复杂度我们都记作 O(1)。

    • O(logn)、O(nlogn)
    i=1;
    while(i<=n) {
        i = i*2;
    }

    x=log2n,所以,这段代码的时间复杂度就是 O(log2n)

    • O(m+n)、O(m*n)

       int cal(int m, int n) {
          int sum_1=0;
          int i=1;
          for(;i<m;++i){
             sum_1 = sum_1 + i;
          }
          int sum_2 = 0;
          int j=1;
          for (;j<n;++j){
             sum_2 = sum_2 + j;
          }
          return sum_1 + sum_2;
       }

    从代码中可以看出,m和n是表示两个数据规模。我们无法事先评估m和n谁的量级大,所以我们在表示复杂度的时候,就不能简单地利用加法法则,省略掉其中一个。所以,上面代码的时间复 杂度就是0(m+n)。

    针对这种情况,原来的加法法则就不正确了,我们需要将加法规则改为: T1(m) + T2(m) = O(f(m) + g(n))。但是乘法法则继续有效: T1(m)*T2(n) = O(f(m) * f(n))。

    1.5 空间复杂度分析

    表示算法的存储空间与数据规模之间的增长关系。

    void print(int n) {
        inti=0;
        int[] a = new int[n];
        for (i; i <n; ++i) {
            a[i] =i* i;
        }
        for(i=n-1;i>=0;--i){
            print out a[i]
        }
    }

    跟时间复杂度分析一样,我们可以看到,第2行代码中,我们申请了一个空间存储变量i,但是它是常最阶的,跟数据规模n没有关系,所以我们可以忽略。第3行申请了一个大小为n的int类型数组,除此之外,剩下的代码都没有占用更多的空间,所以整段代码的空间复杂度就是O(n)。

    我们常见的空间复杂度就是O(1)、O(n)、 O(n2), 像O(logn)、O(nlogn) 这样的对数阶复杂度平时都用不到。而且,空间复杂度分析比时间复杂度分析要简单很多。所以,对于空间复杂度,掌握刚我说的这些内容已经足够了。

    1.6 复杂度增长趋势图:

    最好情况时间复杂度、最坏时间复杂度、平均情況时间复杂度、均摊时间复杂度。

    一、复杂度分析的4个概念
    1.最坏情况时间复杂度:代码在最坏情况下执行的时间复杂度。
    2.最好情况时间复杂度:代码在最理想情况下执行的时间复杂度。
    3.平均时间复杂度:代码在所有情况下执行的次数的加权平均值。
    4.均摊时间复杂度:在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。

    二、为什么要引入这4个概念?
    1.同一段代码在不同情况下时间复杂度会出现量级差异,为了更全面,更准确的描述代码的时间复杂度,所以引入这4个概念。
    2.代码复杂度在不同情况下出现量级差别时才需要区别这四种复杂度。大多数情况下,是不需要区别分析它们的。

    三、如何分析平均、均摊时间复杂度?
    1.平均时间复杂度
    代码在不同情况下复杂度出现量级差别,则用代码所有可能情况下执行次数的加权平均值表示。
    2.均摊时间复杂度
    两个条件满足时使用:1)代码在绝大多数情况下是低级别复杂度,只有极少数情况是高级别复杂度;2)低级别和高级别复杂度出现具有时序规律。均摊结果一般都等于低级别复杂度。

    1、数组

    线性表:   线性表就是数据排成像一条线一样的结构.每个现行表上的数据最多只有前和后两个方向.常见的线性表结构:数组,链表、队列、栈等。

    什么是数组:

    1.  数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据
    2.  连续的内存空间和相同类型的数据(随机访问的前提)。
    3. 优点:两限制使得具有随机访问的特性缺点:删除,插入数据效率低。
    4. 对内存空间要求高,需要一块连续的内存空间。
    • 数组怎么根据下标随机访问的?

    通过寻址公式:a[i]_address = base_address + i * data_type_size
    其中data_type_size表示数组中每个元素的大小,base_address 是首元素地址,i数组下标。

    为何数组插入和删除低效:

    插入:
    若有一元素想往int[n]的第k个位置插入数据,需要在k-n的位置往后移。
    最好情况时间复杂度 O(1)

    如果数组中的数据不是有序的,也就是无规律的情况下,可以直接把第k个位置上的数据移到最后,然后将插入的数据直接放在第k个位置上。

    最坏情况复杂度为O(n)


    平均负责度为O(n)

    2. 低效的插入和删除
    1) 插入:从最好O(1) 最坏O(n) 平均O(n)
    2) 插入:数组若无序,插入新的元素时,可以将第K个位置元素移动到数组末尾,把心的元素,插入到第k个位置,此处复杂度为O(1)。
    3) 删除:从最好O(1) 最坏O(n) 平均O(n)
    4) 多次删除集中在一起,提高删除效率
    记录下已经被删除的数据,每次的删除操作并不是搬移数据,只是记录数据已经被删除,当数组没有更多的存储空间时,再触发一次真正的删除操作。即JVM标记清除垃圾回收算法。

    2、链表

    • 什么是链表

    1.和数组一样,链表也是一种线性表。
    2.从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。
    3.链表中的每一个内存块被称为节点Node。节点除了存储数据外,还需记录链上下一个节点的地址,即后继指针next。

    • 链表的特点

    1.插入、删除数据效率高O(1)级别(只需更改指针指向即可),随机访问效率低O(n)级别(需要从链头至链尾进行遍历)。


    2.和数组相比,内存空间消耗更大,因为每个存储数据的节点都需要额外的空间存储后继指针。

    • 常用链表

    1.单链表


    1)每个节点只包含一个指针,即后继指针。
    2)单链表有两个特殊的节点,即首节点和尾节点。为什么特殊?用首节点地址表示整条链表,尾节点的后继指针指向空地址null。
    3)性能特点:插入和删除节点的时间复杂度为O(1),查找的时间复杂度为O(n)。

    2.循环链表


    1)除了尾节点的后继指针指向首节点的地址外均与单链表一致。
    2)适用于存储有循环特点的数据,比如约瑟夫问题。

    3.双向链表


    1)节点除了存储数据外,还有两个指针分别指向前一个节点地址(前驱指针prev)和下一个节点地址(后继指针next)。
    2)首节点的前驱指针prev和尾节点的后继指针均指向空地址。
    3)性能特点:
    和单链表相比,存储相同的数据,需要消耗更多的存储空间。
    插入、删除操作比单链表效率更高O(1)级别。以删除操作为例,删除操作分为2种情况:给定数据值删除对应节点和给定节点地址删除节点。对于前一种情况,单链表和双向链表都需要从头到尾进行遍历从而找到对应节点进行删除,时间复杂度为O(n)。对于第二种情况,要进行删除操作必须找到前驱节点,单链表需要从头到尾进行遍历直到p->next = q,时间复杂度为O(n),而双向链表可以直接找到前驱节点,时间复杂度为O(1)。
    对于一个有序链表,双向链表的按值查询效率要比单链表高一些。因为我们可以记录上次查找的位置p,每一次查询时,根据要查找的值与p的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。

    4.双向循环链表:

    首节点的前驱指针指向尾节点,尾节点的后继指针指向首节点。

    • 选择数组还是链表?

    1.插入、删除和随机访问的时间复杂度
    数组:插入、删除的时间复杂度是O(n),随机访问的时间复杂度是O(1)。
    链表:插入、删除的时间复杂度是O(1),随机访问的时间复杂端是O(n)。

    2.数组缺点
    1)若申请内存空间很大,比如100M,但若内存空间没有100M的连续空间时,则会申请失败,尽管内存可用空间超过100M。
    2)大小固定,若存储空间不足,需进行扩容,一旦扩容就要进行数据复制,而这时非常费时的。
    3.链表缺点
    1)内存空间消耗更大,因为需要额外的空间存储指针信息。
    2)对链表进行频繁的插入和删除操作,会导致频繁的内存申请和释放,容易造成内存碎片,如果是Java语言,还可能会造成频繁的GC(自动垃圾回收器)操作。
    4.如何选择?
    数组简单易用,在实现上使用连续的内存空间,可以借助CPU的缓冲机制预读数组中的数据,所以访问效率更高,而链表在内存中并不是连续存储,所以对CPU缓存不友好,没办法预读。
    如果代码对内存的使用非常苛刻,那数组就更适合。

    • 应用

    1.如何分别用链表和数组实现LRU缓冲淘汰策略?
    1)什么是缓存?
    缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非广泛的应用,比如常见的CPU缓存、数据库缓存、浏览器缓存等等。
    2)为什么使用缓存?即缓存的特点
    缓存的大小是有限的,当缓存被用满时,哪些数据应该被清理出去,哪些数据应该被保留?就需要用到缓存淘汰策略。
    3)什么是缓存淘汰策略?
    指的是当缓存被用满时清理数据的优先顺序。
    4)有哪些缓存淘汰策略?
    常见的3种包括先进先出策略FIFO(First In,First Out)、最少使用策略LFU(Least Frenquently Used)、最近最少使用策略LRU(Least Recently Used)。
    5)链表实现LRU缓存淘汰策略
    当访问的数据没有存储在缓存的链表中时,直接将数据插入链表表头,时间复杂度为O(1);当访问的数据存在于存储的链表中时,将该数据对应的节点,插入到链表表头,时间复杂度为O(n)。如果缓存被占满,则从链表尾部的数据开始清理,时间复杂度为O(1)。
    6)数组实现LRU缓存淘汰策略
    方式一:首位置保存最新访问数据,末尾位置优先清理
    当访问的数据未存在于缓存的数组中时,直接将数据插入数组第一个元素位置,此时数组所有元素需要向后移动1个位置,时间复杂度为O(n);当访问的数据存在于缓存的数组中时,查找到数据并将其插入数组的第一个位置,此时亦需移动数组元素,时间复杂度为O(n)。缓存用满时,则清理掉末尾的数据,时间复杂度为O(1)。
    方式二:首位置优先清理,末尾位置保存最新访问数据
    当访问的数据未存在于缓存的数组中时,直接将数据添加进数组作为当前最有一个元素时间复杂度为O(1);当访问的数据存在于缓存的数组中时,查找到数据并将其插入当前数组最后一个元素的位置,此时亦需移动数组元素,时间复杂度为O(n)。缓存用满时,则清理掉数组首位置的元素,且剩余数组元素需整体前移一位,时间复杂度为O(n)。(优化:清理的时候可以考虑一次性清理一定数量,从而降低清理次数,提高性能。)
    2.如何通过单链表实现“判断某个字符串是否为水仙花字符串”?(比如 上海自来水来自海上)
    1)前提:字符串以单个字符的形式存储在单链表中。
    2)遍历链表,判断字符个数是否为奇数,若为偶数,则不是。
    3)将链表中的字符倒序存储一份在另一个链表中。
    4)同步遍历2个链表,比较对应的字符是否相等,若相等,则是水仙花字串,否则,不是。
    六、设计思想
    时空替换思想:“用空间换时间” 与 “用时间换空间”
    当内存空间充足的时候,如果我们更加追求代码的执行速度,我们就可以选择空间复杂度相对较高,时间复杂度小相对较低的算法和数据结构,缓存就是空间换时间的例子。如果内存比较紧缺,比如代码跑在手机或者单片机上,这时,就要反过来用时间换空间的思路。

    3、队列

    什么是队列:

    队列是一种受限的线性表数据结构,只支持两个操作:入栈push()和出栈pop0,队列跟非常相似,支持的操作也 ,很有限,最基本的操作也是两个:入队enqueue(),放一个数据到队列尾部;出队dequeue0),从队列头部取一个元素。

    特点:

    1 . 队列跟栈一样,也是一种抽象的数据结构。

    2. 具有先进先出的特性,支持在队尾插入元素,在队头删除元素。

    实现:

    队列可以用数组来实现,也可以用链表来实现。

    用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。

    基于数组的队列:

    实现思路:

    实现队列需要两个指针:一个是head指针,指向队头;一个是tail指针,指向队尾。你可以结合下面这幅图来理解。当a,b,c,d依次入队之后,队列中的head指针指向下标为0的位置, tail指针指向下标为4的位置。

    当我们调用两次出队操作之后,队列中head指针指向下标为2的位置, tail指针仍然指向下标为4的位置.

    随着不停地进行入队、出队操作, head和tail都会持续往后移动。当tail移 . ,动到最右边,即使数组中还有空闲空间,也无法继续往队列中添加数据了。这个问题该如何解决呢?

    在出队时可以不用搬移数据。如果没有空闲空间了,我们只需要在入队时,再集中触 ,发一次数据的搬移操作。

    当队列的tail指针移动到数组的最右边后,如果有新的数据入队,我们可以将 head到tail之间的数据,整体搬移到数组中0到tail-head的位置。

    基于链表的实现: 

    需要两个指针: head指针和tail指针,它们分别指向链表的第一个结,点和最后一个结点。

    如图所示,入队时, tail->next= new node, tail = tail->next:出队时, head = head->next.

    循环队列:

    我们刚才用数组来实现队列的时候,在tail==n时,会有数据搬移操作,这样入队操作性能就会受到影响。那有没有办法能够避免数据搬移呢?我们来看看循环队列的解决思路。循环队列,顾名思义,它长得像一个环。原本数组是有头有尾的,是一条直线。现在我们把首尾相,连,板成了一个环。我画了一张图,你可以直观地感受一下。

    我们可以看到,图中这个队列的大小为8,当前head-4, tail-7,当有一个新的元素a入队时, .我们放入下标为7的位置。但这个时候,我们并不把tail更新为8,而是将其在环中后移一位,到下标为0的位置。当再有一个元素b入队时,我们将b放入下标为0的位置,然后tail加1更新为1,所以,在a, b依次入队之后,循环队列中的元素就变成了下面的样子:

    队列为空的判断条件是head == tail,但队列满的判断条件就稍微有点复杂了。我画了一张队列满的图,你可以看一下,试着总结一下规律,

    就像我图中画的队满的情况, tail=3, head-4, n=8,所以总结一下规律就是: (3+1)%8-4,多画几张队满的图,你就会发现,当队满时, (tail+1)%n=head..你有没有发现,当队列满时,图中的tail指向的位置实际上是没有存储数据的。所以,循环队列会浪费一个数组的存储空间。

    解决浪费一个存储空间的思路:定义一个记录队列大小的值size,当这个值与数组大小相等时,表示队列已满,当tail达到最底时,size不等于数组大小时,tail就指向数组第一个位置。当出队时,size—,入队时size++

    阻塞队列和并发队列(应用比较广泛)

    阻塞队列其实就是在队列基础上增加了阻塞操作。

    简单来说,就是在队列为空的时候,从队头取数 , 据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。

    你应该已经发现了,上述的定义就是一个"生产者-消费者模型" !是的,我们可以使用阻塞队列,轻松实现一个"生产者-消费者模型" !这种基干阴寒队列实现的"生产者-消费者模型" ,可以有效地协调生产和消费的速度。当"生产 , 者"生产数据的速度过快, "消费者"来不及消费时,存储数据的队列很快就会满了。这个时候,生产者就阻塞等待,直到"消费者"消费了数据, "生产者"才会被唤醒继续"生产而且不仅如此,基于阻塞队列,我们还可以通过协调"生产者"和"消费者"的个数,来提高数据,的处理效率。比如前面的例子,我们可以多配置几个"消费者" ,来应对一个"生产者"

    小结:

    队列最大的特点就是先进先出,主要的两个操作是入队和出队。

    它既可以用数组来实现,也可以用链表来实现。用数组实现的叫顺序队列,用链表实现的叫链式队列。

    长在数组实现队列的时候,会有数据搬移操作,要想解决数据搬移的问题,我们就,需要像环一样的循环队列。要想写出没有bug的循环队列实现代码,关键要确定好队空和队满的,判定条件。

    阻塞队列、并发队列,底层都还是队列这种数据结构,只不过在之上附加了很多其他功能。阻塞队列就是入队、出队操作可以阴寒,并发队列就是队列的操作多线程安全。

    4、递归算法

    一、什么是递归?

    1.递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法,比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。
    2.方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。
    3.基本上,所有的递归问题都可以用递推公式来表示,比如
    f(n) = f(n-1) + 1; 
    f(n) = f(n-1) + f(n-2);
    f(n)=n*f(n-1);

    二、为什么使用递归?递归的优缺点?

    1.优点:代码的表达力很强,写起来简洁。
    2.缺点:空间复杂度高、有堆栈溢出风险、存在重复计算、过多的函数调用会耗时较多等问题。

    三、什么样的问题可以用递归解决呢?

    一个问题只要同时满足以下3个条件,就可以用递归来解决:
    1.问题的解可以分解为几个子问题的解。何为子问题?就是数据规模更小的问题。
    2.问题与子问题,除了数据规模不同,求解思路完全一样
    3.存在递归终止条件

    四、如何实现递归?

    1.递归代码编写
    写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后再推敲终止条件,最后将递推公式和终止条件翻译成代码。
    2.递归代码理解
    对于递归代码,若试图想清楚整个递和归的过程,实际上是进入了一个思维误区。
    那该如何理解递归代码呢?如果一个问题A可以分解为若干个子问题B、C、D,你可以假设子问题B、C、D已经解决。而且,你只需要思考问题A与子问题B、C、D两层之间的关系即可,不需要一层层往下思考子问题与子子问题,子子问题与子子子问题之间的关系。屏蔽掉递归细节,这样子理解起来就简单多了。
    因此,理解递归代码,就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。

    递归的关键是终止条件
    五、递归常见问题及解决方案

    1.警惕堆栈溢出:可以声明一个全局变量来控制递归的深度,从而避免堆栈溢出。
    2.警惕重复计算:通过某种数据结构来保存已经求解过的值,从而避免重复计算。

    六、如何将递归改写为非递归代码?

    笼统的讲,所有的递归代码都可以改写为迭代循环的非递归写法。如何做?抽象出递推公式、初始值和边界条件,然后用迭代循环实现。

    5、排序



    一、排序方法与复杂度归类
    (1)几种最经典、最常用的排序方法:冒泡排序、插入排序、选择排序、快速排序、归并排序、计数排序、基数排序、桶排序。
    (2)复杂度归类
    冒泡排序、插入排序、选择排序 O(n^2)
    快速排序、归并排序 O(nlogn)
    计数排序、基数排序、桶排序 O(n)

    二、如何分析一个“排序算法”?
    <1>算法的执行效率
    1. 最好、最坏、平均情况时间复杂度。
    2. 时间复杂度的系数、常数和低阶。
    3. 比较次数,交换(或移动)次数。
    <2>排序算法的稳定性
    1. 稳定性概念:如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。
    2. 稳定性重要性:可针对对象的多种属性进行有优先级的排序。
    3. 举例:给电商交易系统中的“订单”排序,按照金额大小对订单数据排序,对于相同金额的订单以下单时间早晚排序。用稳定排序算法可简洁地解决。先按照下单时间给订单排序,排序完成后用稳定排序算法按照订单金额重新排序。
    <3>排序算法的内存损耗
    原地排序算法:特指空间复杂度是O(1)的排序算法。

    常见的排序算法:


    冒泡排序


    冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足就让它俩互换。

    代码:

      public int[] bubbleSort(int[] a) {
            int n = a.length;
            if (n<=1) {
                return a;
            }
            for (int i = 0; i < n; i++) {
                //提前退出冒泡循环的标志
                boolean flag = false;
                for (int j = 0; j < n-i-1; j++) {
                    if (a[j]>a[j+1]) {//
                        int temp = a[j];
                        a[j] = a[j+1];
                        a[j+1] = temp;
    
                        flag = true;//表示有数据交换
                    }
                    if (!flag) {
                        break; //没有数据交换(说明已排好序无需再进行冒泡),提前退出
                    }
                }
            }
            return a;
        }


    四、插入排序


    插入排序将数组数据分成已排序区间和未排序区间。初始已排序区间只有一个元素,即数组第一个元素。在未排序区间取出一个元素插入到已排序区间的合适位置,直到未排序区间为空。

    代码:

        public int[] insertionSort(int[] a) {
    		int n = a.length;
    		if (n<=1) return a;
    		
    		for (int i = 1; i < n; i++) {
    			int value = a[i];
    			int j = i-1;
    			for (; j >=0; j--) {
    				if (a[j] > value) {
    					a[j+1] = a[j];//移动数据
    				}else {
    					break;
    				}
    			}
    			a[j+1] = value;//插入数据
    		}
    		
    		return a;
    	}


    五、选择排序


    选择排序将数组分成已排序区间和未排序区间。初始已排序区间为空。每次从未排序区间中选出最小的元素插入已排序区间的末尾,直到未排序区间为空。
    代码:

    public int[] selectionSort(int[] a) {
    		int n = a.length;
    		
    		for (int i = 0; i < a.length - 1; i++) {
    			for (int j = i+1; j < a.length; j++) {
    				//交换
    				if (a[i] > a[j]) {
    					int temp = a[i];
    					a[i] = a[j];
    					a[j] = temp;
    				}
    			}
    		}
    		
    		return a;
    	}

    六、归并排序

    如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。

     实现思路:

    merge-sort(p...r)表示,给下标从p到r之间的数组排序。我们将这个排序问题转化为了两个子问 ,题, merge_sort(p...q)和merge-sort(q+1..r),其中下标q等于p和r的中间位置,也就是, (p+r)/2,当下标从p到q和从q+1到r这两个子数组都排好序之后,我们再将两个有序的子数组合并在一起,这样下标从p到r之间的数据就也排好序了。

    代码:

     // 归并排序算法, a是数组,n表示数组大小
      public static void mergeSort(int[] a, int n) {
        mergeSortInternally(a, 0, n-1);
      }
    
      // 递归调用函数
      private static void mergeSortInternally(int[] a, int p, int r) {
        // 递归终止条件
        if (p >= r) return;
    
        // 取p到r之间的中间位置q
        int q = (p+r)/2;
        // 分治递归
        mergeSortInternally(a, p, q);
        mergeSortInternally(a, q+1, r);
    
        // 将A[p...q]和A[q+1...r]合并为A[p...r]
        merge(a, p, q, r);
      }
    
      private static void merge(int[] a, int p, int q, int r) {
        int i = p;
        int j = q+1;
        int k = 0; // 初始化变量i, j, k
        int[] tmp = new int[r-p+1]; // 申请一个大小跟a[p...r]一样的临时数组
       
        // 1 排序
        while (i<=q && j<=r) {
          if (a[i] <= a[j]) {
            tmp[k++] = a[i++]; // i++等于i:=i+1
          } else {
            tmp[k++] = a[j++];
          }
        }
    
        // 2 判断哪个子数组中有剩余的数据
        int start = i;
        int end = q;
        if (j <= r) {
          start = j;
          end = r;
        }
    
        // 3 将剩余的数据拷贝到临时数组tmp
        while (start <= end) {
          tmp[k++] = a[start++];
        }
    
        // 4 将tmp中的数组拷贝回a[p...r]
        for (i = 0; i <= r-p; ++i) {
          a[p+i] = tmp[i];
        }
      }
    

    merge是这样执行的:

    代码分析:

    七、快速排序

    快排的思想:    如果要排序数组中下标从p到r之间的一组数据,我们选择p到r之间的任意一个数据作为pivot (分区点) 。我们遍历p到r之间的数据,将小于pivot的放到左边,将大于pivot的放到右边,将pivot放到中间。经过这一步骤之后,数组p到r之间的数据就被分成了三个部分,前面p到q-1之间都是小于pivot的,中间是pivot,后面的q+1到r之间是大于pivot的。

    快排利用的分而治之的思想

    八、线性排序:

    时间复杂度O(n)

    我们把时间复杂度是线性的排序算法叫作线性排序(Linear sort)常见的线性算法有: 桶排序、计数排序、基数排序

    特点:

    非基于比较的排序算法 

    桶排序

    桶排序,顾名思义,会用到“桶" ,核心思想是将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。

    对排序的数据要求苛刻:

    1, 要排序的数据需要很容易就能划分成m个桶,并且,桶与桶之间有着天然的大小顺序。

    2 ,数据在各个桶之间的分布是比较均匀的。

    3 ,桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。

    计数排序

    计数排序只能用在数据范围不大的场景中,如果数据范围k比要排序的数据n大很多,就不适合用计数排序了。

    计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。

    代码:

     // 计数排序,a是数组,n是数组大小。假设数组中存储的都是非负整数。
      public static void countingSort(int[] a) {
    	int n = a.length;
        if (n <= 1) return;
    
        // 查找数组中数据的范围
        int max = a[0];
        for (int i = 1; i < n; ++i) {
          if (max < a[i]) {
            max = a[i];
          }
        }
    
        // 申请一个计数数组c,下标大小[0,max]
        int[] c = new int[max + 1];
        for (int i = 0; i < max + 1; ++i) {
          c[i] = 0;
        }
    
        // 计算每个元素的个数,放入c中
        for (int i = 0; i < n; ++i) {
          c[a[i]]++;
        }
    
        // 依次累加
        for (int i = 1; i < max + 1; ++i) {
          c[i] = c[i-1] + c[i];
        }
    
        // 临时数组r,存储排序之后的结果
        int[] r = new int[n];
        // 计算排序的关键步骤了,有点难理解
        for (int i = n - 1; i >= 0; --i) {
          int index = c[a[i]]-1;
          r[index] = a[i];
          c[a[i]]--;
        }
    
        // 将结果拷贝会a数组
        for (int i = 0; i < n; ++i) {
          a[i] = r[i];
        }
      }

    散列表

    什么是散列表:

    散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。

    原理:

    散列表用的就是数组支持按照下标随机访问的时候,时间复杂度是0(1)的特性。我们通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。当我们按照键值查询元素时,我们用同样的散列函数,将键值转化数组标标,从对应的数组下标的位置取数据。

    散列函数的设计要求:

    1. 散列函数计算得到的散列值是一个非负整数;.
    2. 如果key1 = key2,那hash(key1) == hash(key2);
    3. 如果key1 != key2,那hash(key1)  !=  hash(key2),

    散列函数的设计不能太复杂,散列函数生成值要尽可能随机并且均匀分布

    如果不符合3 那么就出现了散列冲突,散列冲突是无法避免的

    解决散列冲突的方法有两种: 

    开放寻址法(open addressing)和链表法(chaining)

    开放寻址法:如果出现了散列冲突,我们就重新探测一个空闲位置,将其插入。

    装在因子:  散列表中一定比例的空闲槽位。公式: 散列表的装载因子 = 填入表中的元素个数 / 散列表的长度

    装载因子越大,说明空闲位置越少,冲突越多,散列表的性能会下降。

    链表法:

    链表法是一种更加常用的散列冲突解决办法,相比开放寻址法,它要简单很多。我们来看这个图,在散列表中,每个"桶(bucket) "或者"槽(slot) "会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。

    展开全文
  • 数据结构算法题汇总

    万次阅读 多人点赞 2019-04-13 19:40:07
    3. 算法一般都可以用哪几种控制结构组合而成? 答案:顺序、选择、循环。 4. 算法的时间复杂度是指? 答案:算法执行过程中所需要的基本运算次数。 5. 算法的空间复杂度是指? 答案:执行过程中所需要的存储空间。...
  • Java数据结构算法

    2017-09-09 21:50:29
    Java数据结构算法 Java数据结构算法 Java数据结构算法 Java数据结构算法 Java数据结构算法 Java数据结构算法 Java数据结构算法 Java数据结构算法
  • 数据结构算法(总结)

    千次阅读 2022-04-23 20:25:09
    一、数据结构(Data Structure) 是数据的组织结构,用来组织、存储数据。算法(Algorithm) 就是解决问题的方法或者过程。 二、数据结构分为逻辑结构和物理结构。逻辑结构分为集合结构、线性结构、树形结构、图形...
  • 图解数据结构算法

    万人学习 2020-07-27 10:56:16
    【为什么学习数据结构算法】     程序=数据结构+算法数据结构算法是程序的基础,没有系统地学习过数据结构算法的程序员只能称作是coder,知道我们写的代码使用了什么数据结构,它的特征是什么。...
  • 数据结构算法总结(伪代码)

    万次阅读 2018-06-03 17:01:48
    存储结构:   包含2个域:数据域Data和指针域Link 伪代码实现 typedef struct LNode { //链表结点  ElemType data; //结点数据域  struct LNode * link; //结点链域 ...
  • 按照我下面整理的思路学习,保证能让你大幅提升数据结构算法实践能力! 许多人有这样的疑问,《数据结构算法》理论学习完了,但是做题还是不会;有的同学感觉数据结构算法不知道怎么学习。那看这篇文章就对了...
  • 数据结构算法

    万次阅读 多人点赞 2020-05-19 16:39:12
    数据结构,是指相互之间存在一种或多种特定关系的数据关系的集合,用计算机存储、组织数据的方式。 数据结构分为逻辑结构、物理结构和数据的运算三大部分。 二、为什么要学数据结构 1、因为数据结构作为计算机...
  • 数据结构算法演示系统,动态演示数据结构算法执行过程的辅助教学系统
  • Java 数据结构算法

    千次阅读 2021-02-23 17:06:40
    Java 数据结构
  • LeetCode全部题目和详细解答 数据结构算法 程序员面试求职必备
  • 目录 第一章 C++回顾 函数与参数 1.交换两个整数的不正确代码。 异常 10.抛出并捕捉整型异常。 第一章 C++回顾 函数与参数 1.交换两个整数的不正确代码。 //test_1 void swap(int x,int y) ... int t...
  • 数据结构算法】超多图解,超详细,堆详解

    万次阅读 多人点赞 2021-10-24 10:08:03
    关注专栏:图解数据结构算法(优质好文持续更新中……)???? ???? 欢迎小伙伴们点赞????、收藏⭐、留言???? 目录 ????一、什么是堆 ????二、堆排序 ✨2.1 算法原理 ✨2.2 算法步骤 ✨2.3 实例演示 ✨2.4...
  • 数据结构3.txt 数组完全单元.txt 数组操作.txt 数组递归退出.txt 数组递归退出2.txt 文件加密.txt 文件复制.txt 文件连接.txt 无向图.txt 时间陷阱.txt 杨辉三角形.txt 栈单元加.txt 栈操作.txt 桃子...
  • 408数据结构算法题解

    千次阅读 2020-01-19 18:29:47
    计算机考研408-数据结构 线性表算法题 问题: 删除有序顺序表值在s到t之间的所有元素 我的代码 答案代码
  • JAVA数据结构算法+面试题

    热门讨论 2011-12-19 22:36:17
    有JAVA数据结构算法的教程 还有算法题 加部分面试题 从别人那下的 在这一次给了 希望能帮到大家
  • 数据结构算法之美

    千次阅读 2019-08-31 17:14:58
    数据结构是为算法服务的,算法要作用在特定的数据结构之上。 因此,我们无法孤立数据结构来讲算法,也无法孤立算法来讲数据结构。比如,因为数组具有随机访问的特点,常用的二分查找算法需要用数组来存储数据。但...
  • 什么?程序竟然等于数据结构 + 算法?这个公式是大师 Niklaus Wirth 在 1976 年提出来的,40 多年过去了,这个公式还成立吗?对于做 Java 开发的朋友,可能会更加的赞...
  • 数据结构算法 - PHP

    千次阅读 2019-12-19 10:04:16
    学习数据结构算法, 并且结合PHP, 了解PHP背后实现的原理. 2.学习/操作 暂见:https://xueyuanjun.com/books/data-structure-and-algorithms 后续补充 ... 3.问题 TBD ...
  • 数据结构算法书籍推荐

    万次阅读 多人点赞 2019-03-16 18:49:31
    学习数据结构算法,还是很有必要看几本相关的书籍,但根据不同基础的人,合适看的书也不一样,因此,针对不同层次、不同语言的人,推荐几本市面上口碑不错的书。 1. 入门级 针对刚入门的同学,建议不要急着去看...
  • 877数据结构算法分析

    千次阅读 2021-05-02 18:45:02
    适合考昆明理工大学的877数据结构算法分析,如果考昆工的数据结构算法分析,也可以加入我们的QQ交流群:733804292(初试和复试都是这个) 百度网盘地址: 链接:...
  • 大家好,我是 Rocky0429,一个连数据结构算法都不会的蒟蒻… 学过数据结构算法的都知道这玩意儿不好学,没学过的经常听到这样的说法还没学就觉得难,其实难吗?真难! 难在哪呢?当年我还是个小蒟蒻,初学数据...
  • 数据结构算法三十题,弄懂这些面试就够了!

    万次阅读 多人点赞 2019-02-01 08:30:28
    瑞典计算机科学家 Niklaus Wirth 在 1976 年写了一本书,叫作《Algorithms + Data Structures = Programs》(算法+数据结构=程序)。 即便在 40 年后的今天,这条等式仍然成立。这也是为何程序员求职者应该向面试...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,650,624
精华内容 660,249
关键字:

数据结构 算法

数据结构 订阅
友情链接: 单音音乐.rar