数据结构与算法

                

一、什么是数据结构

            1、数据结构的起源

            1968年,美国的高德纳教授,《计算机程序设计艺术》第一卷

            《基本算法》提出,开创了数据结构与算法的先河

            数据结构是一门专门研究数据之间关系、操作的学科,而非计算数据方法

            数据结构     +     算法        =         程序  (揭露了程序的本质)沃斯凭借这个观点获得了图灵奖

   

    2、数据结构中的基本概念

        数据:任何能够输入到计算机中,能被程序处理的描述客观事物的符号

        数据项:有独立含义的最小单位,也叫做数据域、域

         数据元素:组成数据的、有一定意义的基本单位,也叫做节点(链式表),结点,顶点

            一个数据元素是由若干项数据组成

        数据结构:相互之间存在一种或多种特定关系的数据元素的结合

        算法:数据结构中所具备的功能,能够解决某种问题的方法

    3、研究数据结构的三个方面

                数据的逻辑结构:

            一对一                 一对多                          多对多

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

            顺序存储                 链式存储

        数据结构的运算

    4、数据的逻辑结构

        集合:数据元素同处于同一个集合中,但是元素间没有任何关系

        线性结构(表):数据元素之间存在一对一的关系

        树形结构(树):数据元素之间存在一对多的关系

        图型结构(图):数据元素之间存在多对多的关系

   

    5、数据的存储结构\物理结构

        顺序结构:

            数据元素是存储在连续的内存中,用数据元素的相对位置来表示数据元素之间的关系,

            内存空间是连续的,并且数据元素之间也要确保连续

           

          优点:支持随机访问,访问效率极高,适合查找数据,不容易产生内存碎片

           

          缺点:对数据元素的插入,删除操作效率低,实现不方便(每一次增删都需要挪动后面的所有节点)

        链式结构:

            数据元素存储在彼此独立的内存空间中,每个独立的元素称为节点,每个节点中额外增加一块指针域

            通过该指针可以指向下一个域该节点有关系的节点,以此来表示数据节点之间的关系

           

          优点:对节点的删除,插入操作效率高,实现简单,适合增删数据操作,对内存的空间要求较低

           

          缺点:不支持随机访问,只能从前往后逐一访问,不适合频繁地查找数据,但是容易产生内存碎片        (需要找到任何其中一个节点都需要遍历)

          面试:数组与链表的优缺点?vector 与 list 的优缺点

    6、逻辑结构域存储结构的对应关系

        表:  顺序(数组)、链式(链表)

        树:  链式  、 顺序

        图:  顺序+链式

            注意:每种逻辑结构采用那种存储结构,没有明确规定,通常根据实现的难度、

            空间的要求、时间的要求,综合选择最合适的存储结构

    7、数据结构的运算

        1、建立数据结构              create\creat  

        2、销毁数据结构              destroy

        3、清空数据结构              clear

        4、插入元素                     insert\add

        5、删除元素                     deleat

        6、修改元素                     modify

        7、访问元素                     access

        8、查询元素                     query

        9、遍历数据结构              show\list\ergodic

        10、排序数据结构             sort

二、顺序表的实现

    数据项:

                存储元素的内存首地址                ptr

                表的容量                                     cal

                元素的数量                                 cnt

                           

    运算:

        创建、销毁、清空、插入、删除、访问、查询、修改、排序、遍历

    注意:

        1、要确保数据元素的连续性

        2、不能越界

三、链式表(链表)NO.1  list

            数据元素(节点)的数据项:

                        数据项:可以是各种类型的若干项数据域

                        指针域:指向下一个节点的指针

   

    由若干个节点通过指针域连接起来就形成了链表

    不带头节点的链表:

        定义:第一个节点的数据域存储的是有效数据

    缺点:当插入,删除时可能会修改第一个有效节点,传递的参数需要传递二级指针,实现时需要分是否是操作第一个有效节点,较为麻烦

    带头节点的链表:

        定义:第一个节点作为头节点,数据域不适用不存储有效数据,它的指针域永远指向链表的第一个有效数据节点,就算链表长度为0,头节点依然存在

    优点:当插入,删除时是不会改变头节点的指向,只需要改变它的next,因此无需传递头节点的二级指针,并且实现时无需区分两种情况

        注意:有效节点的处理必须从头节点的next开始,

        笔试题时,如果题目没有说明链表是否带头节点,应该两种情况都分析

四、功能受限制的表结构

    对表结构的功能加以限制形成特殊的表结构

    1、栈:

                只有一个出入口的表结构,先进后出,FILO表(First In Last Out)

                        

                        顺序栈:

                            数据项:

                                        存储元素的内存首地址

                                        栈的容量

                                        栈顶位置

            运算:

                创建、销毁、入栈、出栈、栈顶、栈空、栈满、数量

        常见的栈的笔试题:

            1、某序列为入栈序列,判断哪个序列为正确\不正确的出栈序列

                入栈序列:1 2 3 4 5

                出栈序列:1 2 3 4 5   true

                                 5 4 2 1 3   false

                                 3 2 1 5 4   true

            2、实现一个函数,判断序列b是否是序列a的出栈序列

            int a[5] = {1,2.3,4,5},b[5] = {1,2,3,4,5};

            is_pop(a,b,5)

            bool is_pop(int* a,int* b,len)

            {

                //创建一个栈

                //按a顺序一个个入栈

                //入栈一个就按b顺序出栈

                //结束后判断是否空栈

            }

            3、两个顺序栈,如何安排入栈方向可以让内存使用率最大化?

                让两个顺序栈相邻,且让入栈方向相对入栈,能够让内存空间利用率最大化

           

            4、栈相关的概念:

                假设栈容量为cal

            空增栈:

                top:从0开始   先入栈,再top++

            满增栈:

                top:从-1开始  先top++,再入栈

            空减栈:

                top:从cal-1开始  先入栈,再top--

            满减栈:

                top:从cal开始   先top--,再入栈

                链式栈:

                            数据项:

                                        栈顶指针:

                                        节点数量:

            运算:

                创建、销毁、入栈、出栈、栈顶、栈空、数量

           

        栈的应用:

        1、栈内存的数据存储方式

        2、函数的调用

        func1()

        {

            func2()

            {

            }

        }

        3、生产者与消费者模型(仓库:可用栈来实现)

        4、表达式解析

        a+b*c/2 中缀表达式

        计算机中以后缀表达式来存储      中缀转后缀表达式使用栈

  2、队列:  

                只有两个口进出数据,一个专门近入数据,另一个专门出数据,先进先出,FIFO表(First In First Out)

       

                顺序队列:

                            存储元素的连续内存的首地址

                            容量

                            队头位置    (出队)

                            对尾位置    (入队)

                          【元素的数量】  (【】可加可不加)

            运算:创建、销毁、清空、出队、入队、队空、队满、队头、队尾、元素数量

           

            需要注意的问题

            1、存储元素是由一维数组存储的+队头位置front+队尾位置rear来表示,入队时是rear+1,出队fornt+1,出队rear,为了让队列能够反复使用,我们需要把一维数组想象成一个环,因此+1之后都需要对容量cal求余

                    front = (front+1)%cal

                    rear  = (rear+1)%cal

            2、判断队空队满问题

                如果不处理该问题,呢么队空和队满的条件都是

                front == rear,呢么就无法区分是队空还是队满

                方法1:存储元素的内存多增加一个位置空间

                    队空:front ==rear

                    队满:(rear+1)%cal==front

                    代价:需要额外申请存储一个元素的内存

                           

                    计算数量: (rear->front+cal)%cal

                    队尾数据下标:(rear-1+cal)%cal

                方法2:顺序队列结构中增加一个记录元素数量的数据项,通过数量与容量对比判断队空、队满

            链式队列:

                        由若干个节点组成的队列结构,只能操作队头节点,队尾节点

                                链式队列结构:

                                                    队头指针

                                                    队尾指针

                                                    节点数量

       

        运算:创建、销毁、队空、入队、出队、队头、队尾、数量

    队列的应用:

        1、数据排队处理-消息排队

        2、树的层序遍历

        3、图的广度优先遍历BFS

        4、封装线程池、数据池

            常考的面试、笔试题:

                    请使用两个栈来模拟一个队列的出队,入队功能(栈结构功能都已实现,可以直接使用)

                    typedef struct Queue

                    {

                        ArrayStack* s1;

                        ArrayStack* s2;

                    }Queue;

                1、s1负责入队、s2负责出队

                2、当s2为空时s1非空时,出队时,从s1转移到s2时,s1需要全部转移

                3、s2、s1非空时,优先出s2,直到s2出完,可以继续从s1转移到s2继续出队,

                直到s1、s2都为空时才队空

                4、s2空s1满时,入队时需要s1全部转移到s2,入s1

                5、s1、s2满时不入队,s1满s2非空也不入队

封装链表:

    1、单链表

        由于不封装链表结构时,链表的尾添加效率低

        其次非法位置的判断效率也很低,只能通过遍历来判断

                            节点:

                                        数据域

                                        指针域next

                            链表结构:

                                                头指针

                                                尾指针

                                                节点数量

        注意:单链表的删除节点,无论是按位置,按值删除,都需要找到待删除节点的前一个节点

    2、静态链表

                                节点:

                                            数据域

                                            游标

                        特点:

        1、静态链表的节点存储在一段连续的内存中,通过游标来访问下一个节点

        2、插入、删除节点时,只需要修改游标的值即可,不需要动态申请、释放节点,因此得名静态链表

        3、但是也牺牲了随机访问的功能、对内存的要求高,只是给没有指针的编程语言提供实现链表的方式

    3、循环链表

        链表的最后一个节点的next不指向NULL,而是指向第一个节点,这种链表称为循环链表,如果是单链表

        则称为单循环链表,好处是可以任意一个节点开始遍历整个链表

   4、双向链表  (循环)

        注意:双向链表一般会实现为双向循环链表,最后一个节点的next指向第一个节点,第一个节点的prve

        指向最后一个节点

        节点:  

            前驱指针    prve

            数据域      data

            后继指针    next

        封装双循环链表结构:

            头节点指针  head

            节点数量    cnt

            注意:封装的是带头节点的双链表,不然的话插入、删除操作可能会改变head的指向,处理

            起来就需要分情况且麻烦,因此带头节点不需要考虑以上情况

            注意:

            1、删除操作时,不再需要找待删除节点的前一个位置

            2、因为是双向循环链表,所以可以根据需要从前往后遍历,

            也可以从后往前遍历,从而提高查找效率

    5、Linux内核链表

        既然节点中不能包含万物,呢么就让万物来包含节点

    6、通用链表

        能够存储并操作任意类型的数据到链表中,并提供对应的操作

            万能指针 void*

                c语言中     任意类型的指针可以转换成void* 类型

                            void*类型指针可以转换成任意类型的指针

            节点:

                void* ptr; //  数据域

                指针域;

            链表结构:

                头指针

                数量

            核心点:

            1、void*确保能存储任意类型数据

            2、普遍操作可参观双链表即可

            3、通过回调模式来实现一些特殊操作,例如:遍历,按值操作,排序                


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值