zoukankan      html  css  js  c++  java
  • 链队列

    哎,又是你们,都快双11了,打赏一下小编吧。(另外发现多行空格打字好像不能表示,所以这里就把代码涂红了,有点鲜艳,-_-)

    言归正传,今天我们讲讲链队列,头文件那些上次讲过了,差不多,我就不再赘述了。

    我们先讲讲队列的特性:先进先出

    (这里说一下,此图取自Leetcode)

    在 FIFO 数据结构中,将首先处理添加到队列中的第一个元素。

    如上图所示,队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素。

    为了实现插入和删除操作,我们需要用到一个数组来存储元素和指针移到,另外还需要两个指针front和rear来表示队列的头部和尾部(所以其实我们可以把它当成循环队列来理解。)

    那么目标明确了,就先定义结构体了。

    typedef struct node
    {
      elemtype data;                             //元素
      struct node *next;                         //移到的指针设置
    }QNode,*queuenode;                          //QNode是数组,后面那个就是数组的指针形式了,可以这么理解的,名称自己随意了,最好是能表达意思的那种
    typedef struct
    {
      queuenode front, rear;                  //这里的定义其实是多变的,但是归根结底还是要把这两个设置为指针型。
    }linkqueue;                                           //这里的定义其实也是多变的,你可以定义为指针型,都OK的,但是数组简单一点,就这样了。

    1,插入(也就是入队)

    这里补充一下,为什么今天没有定义函数了呢,因为队列的定义相对简单,直接在主函数里实现就好了。(但还是要尽可能的保持主函数的简洁性)

    再来剖析一下入队操作:1,基础的分配空间;2,插入必备的赋值,和地址转换

    status enqueue(linkqueue *Q, elemtype e){                    //可能有同学会问,为什么我的是*Q,因为我上面的第二个数组我只设置了数组类型名,我想用地址来做,所以就加*号了,这里看大家习惯了。除此之外,我这里讲一下,不知道讲过没有,还是讲一下,数  组的指针的引用区别:数组是加“.” ,而指针则是用“->” 。
    queuenode p;
    p=(queuenode) malloc (sizeof (QNode));
    if(!p) exit (ERROR);
    p->data = e;
    p->next = NULL;                                                              //大家还没有忘记我们上面放的那个图吧,队列是先进先出,所以它的插入都是插在后面,也就是说插进来的那个元素的next始终指向NULL。
    Q->rear->next = p;                                                           //这里有没有那个小伙伴有问题的啊,好,没有,下一个
    Q->rear = p;                                                                      //开玩笑开玩笑,为什么这里会用rear呢,按理来说,插入不是应该要头结点的next吗?大家再好好想一想我们一开始的那个图,队列是先进先出,也就是说只有队尾是在移动的,是能够用了插入的,你一直用front那岂不是每次插入的都是同一个位置,是吧,当然,你可以再中间断开,但那样麻烦的十我是不会做的。
    return OK;                                                                          //想必有小伙伴已经发现了一个问题了,嘿嘿,我先不说
    }

    2,删除(也就是出队)

    剖析剖析,删除之基本操作:1,弹出去一个元素,其他的补上去,呸,我呸,知不知道那样的时间复杂度为O(n),队列队列,一开始设置那个头结点用来干什么的,好看的吗(当然不包括上面发现问题的同学们的那个东西),这时我们就可以通过移动头结点来进行删除操作了,这样的时间复杂度就少了太多了,2,切记要free空间,虽然系统自己会清理掉,但写出来就是加分项哦

    status dequeue(linkqueue *Q, elemtype *e){                        //Q我不管你们怎么定义了,但是e一定要用指针,其实要作出改变的对象应该都要用*的,也就是指了(好习惯)
    queuenode p;
    if(Q->front == Q->rear) return ERROR;                                 //好了好了,现在我们来说说上面发现的那个问题,我一开始是不是说了这是一个循环队列,循环循 环,那是不是总有一天front会跟rear碰上,这就是一个目前为止最能体现出插人函数分配空间的用处的了,因为每次插入,我们都会给它分配空间,所以它是可以无限插入直到电脑不行了的。

                                                                                                    //那碰上了,怎么办。碰上了就代表到头了,也就是循环一遍了,那删除一开始,还没开始动,就头了,那肯定就是一个空队列了,就要退出了。
    p = Q->front->next;                                                                  //移移移移动头结点
    *e = p->data;
    Q->front->next = p->next;                                                        //这里是必须要指一下next的哦,大家还记得链表吗,头结点位于第一个元素前面一点点
    if(Q->rear ==p)Q->rear = Q->front;                                          //这里是什么意思,就是代表着队列里只有一个元素
    free(p);
    return OK;
    }

    好了好了,插入和删除就到这里结束了,再给大家讲一下print函数吧

    剖析again,怎么输出呢,有很多方法:1,从头结点开始遍历,2,我们一开始不是有定义一个数组吗,可以通过数组输出,3,因为是循环队列,从队尾开始也是OK的。(这里讲讲第一种,比较常用的)

    void printf_Q(linkqueue Q){
    int i;
    Q.front=Q.front->next;                                          //注意一开始必须要指一下next,原因上面讲过了
    if(Q.front==Q.rear) return ERROR;                      //一样的,空就退出
    for(i=0;;i++){
    printf("%d ",Q.front->data);                                   //输出就很简单了,因为结点也是定义的数组指针,所以直接值向data就好了
    if(Q.front!=Q.rear)                                                 //直到他们碰上,就代表已经循环了一遍了
    Q.front=Q.front->next;
    else
    break;
    }

    }

    老师还有布置一个返回长度的函数吧,那个跟print其实差不多,就不赘述了。

    附:主函数:

    void main()
    {
    QNode Q0; linkqueue Q; elemtype x;
    Q0.next=NULL;
    Q.front=&Q0; Q.rear=&Q0;
    enqueue(&Q,3); enqueue(&Q,55); enqueue(&Q,2); enqueue(&Q,9); enqueue(&Q,7);
    enqueue(&Q,32); enqueue(&Q,66);
    printf("长度为:%d, 元素为:", length_Q(Q));printf_Q(Q);
    dequeue(&Q,&x); dequeue(&Q,&x);
    printf(" 长度为:%d, 元素为:", length_Q(Q));printf_Q(Q);
    enqueue(&Q,77);
    printf(" 长度为:%d, 元素为:", length_Q(Q));printf_Q(Q);
    }

     

    大家,下次再见吧(再说)!!!

  • 相关阅读:
    信息收集之Nmap
    namp ssl秘钥安全性检测
    msf测试tomcat
    MobaXterm root用户连接虚拟机时出现Access denied
    最长公共子序列C
    web 入门58-70
    oninput,onpropertychange,onchange的用法和区别
    JavaScript判断图片是否加载完成的三种方式---转
    node.js
    SPP-Net
  • 原文地址:https://www.cnblogs.com/tqdlb/p/11755388.html
Copyright © 2011-2022 走看看