数据结构与算法整理--2(郝兵)

版权声明:本文为博主原创文章,转载请注明来源 https://blog.csdn.net/C1664510416/article/details/82948380

16.复习

数据结构: 

    狭义:

        数据结构是专门研究数据存储的问题

        数据的存储包括:个体存储 + 个体之间关系的存储

    广义:

        数据结构既包括数据的存储也包括数据的操作

        对存储数据的操作就是算法。

算法:

    狭义:

        算法是和数据存储密切相关的

    广义:

        算法和数据的存储方式无关

        这就是泛型思想

数据的存储结构:

        线性存储

                连续存储【数组】

                        优点:存取速度很快

                        缺点:插入删除元素很慢,空间通常有限制

                非连续存储【链表】

                        优点:空间没有限制

                                  插入元素很快

                        缺点:

                                存取速度很慢

                线性结构的应用:

                                栈

                                队列

        非线性存储

                树

                图

17.栈

定义:

       一种可以实现“先进后出”的存储结构。

分类:

        静态栈

        动态栈

算法:

        出栈

        压栈

栈程序的演示: 

应用:

        函数调用

        中断

        表达式求值

        内存分配

        缓冲处理

        迷宫

18.队列   

定义:一种可以实现“先进先出”的存储结构。

    分类:

        链式队列:

            用链表实现

        静态队列:

            用数组实现

            静态队列,通常都是循环队列

      循环队列:

    1.静态队列为什么要是循环队列

            因为不论是从头部(  front )删除,还是从尾部(rear)增加,地址都在向“后”移动,若不循环,终究会将申请的内存耗尽。

    2.循环队列需要几个参数来确定

            需要2个参数来确定,2个参数不同的场合有不同的意义。(front  rear)

                1).   队列初始化(front  和 rear 的值都是零),

                2).   队列非空(front 代表的是队列的第一个元素,  rear 代表的是队列的最后一个有效元素的,后一个元素),

                3).   队列空(front 和 rear的值相等,但不一定是零)

    3.循环队列需要几个参数来确定

                    2个

    4.循环队列入队伪算法

            两步搞定:

                1.将值存入r所代表的位置

                2.r=(r+1)%数组的长度

    5.循环队列出队伪算法

            一步搞定:

                1.f=(f+1)%数组的长度

    6.如何判断循环队列是否为空

                看 front  与  rear  的值是否相等,若相等,则一定为空。

    7.如何判断队列是否已满

                两种方式:多增加一个标志来存放数量。

                                 少用一个元素来判断。

                如果紧挨着就是满了,

                        伪算法:

                                 if( (r + 1)%数组的长度== f )

                                                    满了

                                    else

                                                    不满

18.求链表的长度

while(p->pNext!=NULL)
{    
        cnt++;
        p=p->pNext;
}

19.复习—队列

队列:
            定义:一种可以实现先进先出的存储结构。
            分类:  静态队列:数组实现,数组实现的队列都是循环队列。
                        链式队列:

循环队列:
    1.静态队列为什么要是循环队列
            因为不论是从头部(  front )删除,还是从尾部(rear)增加,地址都在向“后”移动,若不循环,终究会将申请的内存耗尽。
    2.循环队列需要几个参数来确定
            需要2个参数来确定,2个参数不同的场合有不同的意义。(front  rear)
                
                1).   队列初始化(front  和 rear 的值都是零),
                2).   队列非空(front 代表的是队列的第一个元素,  rear 代表的是队列的最后一个有效元素的,后一个元素),
                3).   队列空(front 和 rear的值相等,但不一定是零)


    3.循环队列需要几个参数来确定
                    2个
    4.循环队列入队伪算法
            两步搞定:
                1.将值存入r所代表的位置
                2.r=(r+1)%数组的长度
    5.循环队列出队伪算法
            一步搞定:
                1.f=(f+1)%数组的长度
    6.如何判断循环队列是否为空
                看 front  与  rear  的值是否相等,若相等,则一定为空。
    7.如何判断队列是否已满
                两种方式:多增加一个标志来存放数量。
                                 少用一个元素来判断。
                如果紧挨着就是满了,
                        伪算法:
                                 if( (r + 1)%数组的长度== f )
                                                    满了
                                    else
                                                    不满

20.循环队列的程序演示



#include <stdio.h>
#include <malloc.h>
typedef struct Queue
{
    int *pBase;
    int front;
    int rear;
}QUEUE;

void init(QUEUE*);        //创建队列
bool en_queue(QUEUE *,int);   //入队
void travel(QUEUE *);     //遍历
bool full_q(QUEUE *);    //队列是否已满
bool out_q(QUEUE *,int*);  //出队
bool empty_q(QUEUE *);   //队列是否为空

int main(void)
{
    QUEUE Q;
    init(&Q);
    int val=0;
    en_queue(&Q,1);
    en_queue(&Q,2);
    en_queue(&Q,3);
    en_queue(&Q,4);
    en_queue(&Q,5);
    en_queue(&Q,6);
    en_queue(&Q,7);
    en_queue(&Q,8);
    travel(&Q);
    if(out_q(&Q,&val))
    {
        printf("出队元素是%d\n",val);
    }else{
        printf("出队失败!\n");
    }
    
    if(out_q(&Q,&val))
    {
        printf("出队元素是%d\n",val);
    }else{
        printf("出队失败!\n");
    }
    
    travel(&Q);
    return 0;
}


bool empty_q(QUEUE *pQ)
{
    if(pQ->front ==pQ->rear)
    {
        return true;
     }else{
         return false;
     }
}


bool out_q(QUEUE *pQ,int *pVal)
{
    if(empty_q(pQ))
    {
        return false;
     }else{
         *pVal=pQ->pBase[pQ->front];
         pQ->front=(pQ->front +1)%6;
         return true;
     }
    
}


void init(QUEUE *pQ)    //创建队列
{
    pQ->pBase=(int *)malloc(sizeof(int)*6);
    pQ->front=0;
    pQ->rear=0;
    
}
void travel(QUEUE* pQ)
{
    int i=pQ->front;
    while(i!=pQ->rear)
    {
        printf("%d",pQ->pBase[i]);
        i=(i+1)%6;
     }
    
}


bool full_q(QUEUE *pQ)
{
    if((pQ->rear +1)%6==pQ->front )
    {
        return true;
    }else{
         return false;
    }
}


bool en_queue(QUEUE *pQ,int val)
{
    if(full_q(pQ))
    {
        return false;
    }else{
         pQ->pBase[pQ->rear]=val;
         pQ->rear =(pQ->rear + 1)%6;
         return true;
    }
}

21.队列的具体应用

    所有和时间有关的操作都与队列有关。

22.递归

函数互相调用的流程。

递归定义:一个函数自己直接或间接调用自己。

(判断流程为否时,代码可以当作没有写)

程序举例:

#include <stdio.h>

void f(int n)
{
    if(n==1)
    {
        printf("哈哈\n");
    }else{
        printf("嘿嘿\n");
        f(n-1);
    }
    
    return;
}

int main()
{
    f(5);
    
    
    return 0;
}



23.递归的几个例子

实现递归的条件:函数调用其本身,设置正确的结束条件。

1.求阶乘:
        循环实现:

#include <stdio.h>

int main()
{
    int val;
    int i,sum=1;
    printf("请输入一个数字: Val=");
    scanf("%d",&val);
    
    for(i=1;i<=val;i++)
    {
        sum=sum*i;
    }
    printf("sum=%d\n",sum);
    return 0;
}
       阶乘的递归实现:

#include <stdio.h>

int f(int n)
{
    if(1==n)
    {
        return 1;
    }else{
        return f(n-1)*n;
    }
}
int main()
{
    int i=0,n=0;
    printf("请输入一个数:n=");
    scanf("%d",&n);
    i=f(n);
    printf("%d的阶乘是%d\n",n,i);
    return 0;
}

24.递归实现汉诺塔



#include <stdio.h>
void hanoi(int n,char x,char y,char z);

int main()
{
    int n;
    printf("请输入汉诺塔的层数:");
    scanf("%d",&n);
    hanoi(n,'x','y','z');
    return 0;
}
void hanoi(int n,char x,char y,char z)
{
    if(n==1)
    {
        printf("%c->%c\n",x,z);
     }else{
         hanoi(n-1,x,z,y);
         printf("%c->%c\n",x,z);
         hanoi(n-1,y,x,z);
     }
    
}

25.一个函数为什么可以自己调用自己(递归)

递归:一个函数直接或间接调用自己。

直接调用自己:在自己的函数里直接调用自己。

void sum(int n)
{
        return sum(n);
}
间接调用自己:通过一个函数的传递调用自己。

void f(int n)
{
    g(n);
}

void g(int n)
{
    f(m);
}


一个函数为什么可以自己调用自己:

代码块只有一块存储空间。存储区,代码区的执行是互相不影响的。

26.递归必须满足三个条件

递归必须满足的条件:

        1.递归必须有一个明确的终止条件。

        2.该函数处理的数据规模必须在递减。

        3.这个转化必须是可解的。

        学习:搞懂递归的经典算法

27.递归和循环的比较

        循环和递归:

            递归:易于理解(树),速度慢,存储空间大

            循环:浪费空间少,存储空间少

28.汉诺塔

伪算法:
    如果是一个盘子
            直接将A柱子上的盘子从A移到C
    否则
            先将A上的n-1借助C移到B上
            直接将A柱子上的第n个盘子移到C上
            再将B柱子上的n-1个盘子借助A移到C上

#include <stdio.h>

void hanoi(int n,char x,char y,char z);     //X 代表放盘子的柱子,Y代表借助的柱                                                                     子,Z代表移到的柱子

int main()
{
    int n;
    printf("请输入汉诺塔的层数:");
    scanf("%d",&n);
    hanoi(n,'x','y','z');
    return 0;
}
void hanoi(int n,char x,char y,char z)
{
    if(n==1)
    {
        printf("%c->%c\n",x,z);
     }else{
         hanoi(n-1,x,z,y);
         printf("%c->%c\n",x,z);
         hanoi(n-1,y,x,z);
     }
    
}

29.递归的应用

树和森林就是以递归的方式定义的;

数和图的很多算法都是以递归来实现的;

很多数学公式就是以递归的方式定义的;

                                    斐波那契数列:1  2  3  5  8  13  21

猜你喜欢

转载自blog.csdn.net/C1664510416/article/details/82948380