• 考研数据结构-单链表(综合应用1)


    本节题目来自王道单科37页。说不定哪天就放弃了在电脑上敲代码了,好费时啊啊啊啊。

    1、设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

    终止条件:F(L,x)不做任何事情;                                         若L为空表      

    递归主体:F(L,x)删除*L结点;并递归下一层F(L->next,x)    若L->data==x

         递归下一层F(L->next,x)                                    其他情况     

    void R_delete(LinkList &L,int x){
    //设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
        LNode *s;
        if(L==NULL)return;
        if(L->data==x){
            s=L;
            L=L->next;
            free(s);
            R_delete(L,x);
        }
        else{
            R_delete(L->next,x);
        }
    } 

    2、在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一。

    void del_x2(LinkList &L,int x){
        LNode *pre=L,*p=L->next;
        LNode *q;
        while(p!=NULL){
            if(p->data==x){
                q=p;
                pre->next=p->next;
                p=p->next;
    free(q);
            }
            else{ 
                pre=p;
                p=p->next;
            }
        }
    }

    删除操作大总结:

    ①这里的删除操作是定义了一个新指针来指向要删除的结点,然后释放这个指针就相当于释放了它指向的结点。

          p是要删除的结点,pre是删除结点的前驱结点,定义一个新指针q指向要删除的结点。具体是下面这样:
    q=p; pre->next=p->next; p=p->next; //这里只是p要继续往下遍历。r如果不用遍历可以不用到这句。 free(q);

    ②其实还有一种删除的方法,可以不用定义新指针。下面这段代码可以代替上面几行。且更常用。

            pre->next=p->next;

       free(p);

       p=pre->next;           //遍历也不会丢失地址,因为pre->next刚好有记到。如果不用遍历可以不用到这句。

    ③如果遍历的时候不在乎所删除结点的前驱结点要和后面连接起来,而可以边遍历边释放的话,甚至可以没有pre指针。

    直接用q指向要删除的结点,p继续往后遍历,然后释放掉q就ok了。

    q=p;   p=p->next;   free(q);  即可。这句和上面第一种只是少了前驱结点和后面的连接,即pre->next=p->next;

    下面这段代码用到的就是这种情况。

    void del_x3(LinkList &L,int x){
        LNode *p=L->next,*r=L,*q;
        while(p!=NULL){
            if(p->data!=x){
                r->next=p;
                r=p;       //尾插法的典型代码。r->next=p;r=p; 其中r=p可以用r=r->next代替,都表示r向后移动 
                p=p->next;  //继续遍历 
            }
            else{
                q=p;   //删除p所指结点,释放空间 
                p=p->next;
    free(q);  
            }
        }
        r->next=NULL;
    }

    3、设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

    分析:①反向第一个想到栈,②进而想到递归。③当然也可以头插法,④或者改变链表指针的方向,即下面第5题。

    void R_print(LinkList L){
        if(L->next!=NULL){
            R_print(L->next);
        }
        printf("%d ",L->data);
    } 

    4、在单链表L中删除一个最小值结点(假设最小值结点是唯一的)

    分析:因为只删除一个结点,要考虑前驱结点,所以我们考虑上面的删除操作中的第二个,即pre->next=p->next;   free(p);

      找最小值类似于顺序表先定义一个min=第一个,然后往后遍历逐步比较,只要后面有就更新min值。因为此处是删除最小值结点,我们也用结点类型来定义,即LNode *minp;又因为删除的时候要注意前驱结点,则再设一个LNode *minpre,始终在minp前面。

    void Min_Delete(LinkList &L){
        LNode *pre,*p;
        LNode *minpre,*minp;
        while(L->next!=NULL){
            pre=L;minpre=pre;
            p=L->next;minp=p;
            while(p!=NULL){
                if(p->data<minp->data){
                    minpre=pre;       //更新minp,使其指向新找到的更小的结点
                    minp=p;
                }
                pre=p;
                p=p->next;  //往后遍历
            }
            printf("%d ",minp->data);
            minpre->next=minp->next;
            free(minp);
        }    
    }

    这道题和王道第9题相似,区别只在于前者只删除一个结点,后者删除所有结点。所以后者在外层加上一个while(L->next!=NULL)

    void Min_Delete(LinkList &L){
        LNode *pre,*p;
        LNode *minpre,*minp;
        while(L->next!=NULL){
            pre=L;minpre=pre;
    p=L->next;minp=p;
    while(p!=NULL){
                if(p->data<minp->data){
                    minpre=pre;
                    minp=p;
                }
                pre=p;
                p=p->next;
            }
            printf("%d ",minp->data);
            minpre->next=minp->next;
            free(minp);
        }    
    }

    5、编写算法将带头街的单链表“就地”逆置,即空间复杂度为O(1)

    ①头插法

    LinkList Reverse1(LinkList &L){
        LNode *p,*q;
        p=L->next;
        L->next=NULL;   //容易忘记 ,要养成好习惯。 
        while(p!=NULL){
            q=p->next;   //用新的指针记住p的后继结点的位置,防止断链
            p->next=L->next;
       L->next=p;   //头插法的典型代码,要记住
            p=q;
        }
        return L;
    }

    ②p每往后遍历就修改指针,将其next指向上一个指针,这个设一个新指针pre来记录,就像删除操作的时候一样。

    LinkList Reverse2(LinkList L){
        LNode *pre,*p=L->next,*r=p->next;
        p->next=NULL;           //处理第一个结点,就像链表中的尾结点r->next=NULL。这是反转后的链表,也要这样处理。
        while(r!=NULL){           //如果r为空,则说明p为最后一个结点。
            pre=p;
            p=r;
            r=r->next;       //可理解为三个指针都向后移动
            p->next=pre;         //指针反转      
        }
        L->next=p;      //处理最后一个结点,把头结点指向最后结点,实现最终反转。
        return L;
    }
  • 相关阅读:
    数据结构之整数划分问题(转)
    各种排序方法的收集
    bloom filter 的Java 版
    常见面试题学习(3)
    优先级队列的Java ,C++ STL,堆实现
    常见面试题学习(2)
    常见面试题学习(5)
    常见面试题学习(4)
    常见面试题学习(1)
    bitmap与桶方式对1000万数据进行排序(转+自己实现理解)
  • 原文地址:https://www.cnblogs.com/double891/p/9131086.html
Copyright © 2020-2023  润新知