一.单链表习题(2)

二.2王道课后题

第二部分

8

image-20210410124419674

常规思路是暴力解法时间复杂度o(len1*len2)

我的代码和书上代码不一样,但是理念一样

假如两个链表有公共结点那么,一定在某个结点开始,一直到最后一个结点,都是公共的.

也就是从最后一个结点开始,往前n个结点是相同的.

只要先知道两个链表的长度,然后在长度相同的时候同时遍历,next相同就找到了.

时间复杂度o(len1+len2)

代码
//在结点后插入结点的方法
bool insertOrder(LNode *l,int num,LNode *q){
   /*  头节点不插入值 所以插入位置只能从1开始
        if (num==0){
        l->data=e;
    } */
    if(num<1){
        cout<<"位序有误"<<endl;
        return false;
    }
    /* 第一个节点 应该位序是0
    int i=1;
    LNode *p=l; */
    int i=0;
    LNode *p =l;
    //找到第i-1个位置,好来插入 
    //插入第一个节点 可以直接找到第0个位置
    while(i<(num-1)&&p!=NULL){
        p=p->next;
        i++;
    }
    //注意别忘了这个 插入了不存在的位置 num大于长度
    if(p==NULL){
        cout<<"位序有误"<<endl;
        return false;
    }
    q->next=p->next;
    p->next=q;
    return true;

}
LNode* findCommonLNode(LinkList &l1,LinkList &l2){
    int len1=length_H(l1);
    int len2=length_H(l2);
    int i;
    int j; //长度差
    LNode *p;
    LNode *q;
    if(len1>=len2){ //先遍历l1 长度差
        j=len1-len2;
        i=0;
        p=l1->next;
        while(i<j){           
            p=p->next;
            i++;
        }
        q=l2->next;
        //此时假如第一个就相同,就会找到第二个长度相同的
        //while(p->next!=q->next&&p!=NULL){
        while(p!=q&&p!=NULL){  
            p=p->next;
            q=q->next;
        }
        return p;
    }
    //if(len1<len2){  // 未返回 非1长 肯定2长
        j=len2-len1;
        i=0;
        q=l2->next;

        while(i<j){           
            q=q->next;
            i++;
        }
        p=l1->next;
        while(p!=q&&p!=NULL){
            p=p->next;
            q=q->next;
        }
        return p; //找不到一定在末尾,返回NULL
    //}
   // return 
}


演示
LinkList l;
    initList_H(l);
    LinkList n;
    initList(n);  //通过初始化不带头结点的链表
    insertListByOrder(n,1,99);
    insertListByOrder_H(l,1,1);
    insertListByOrder_H(l,2,8);
    insertListByOrder_H(l,3,9);
    insertOrder(l,4,n);
    insertListByOrder_H(l,5,5);
    printList_H(l);

    LinkList l2;
    initList_H(l2);
    insertListByOrder_H(l2,1,1);
    insertListByOrder_H(l2,2,4);
    insertListByOrder_H(l2,3,3);
    insertListByOrder_H(l2,4,2);
    insertListByOrder_H(l2,5,5);
    //insertOrder(l2,5,n);  //有公共结点
    cout<<"---------------"<<endl;
    printList_H(l2);
    // reverse01(l);
    if(findCommonLNode(l,l2)!=NULL){
        cout<<"公共结点"<<findCommonLNode(l,l2)->data<<endl;
    }else{
        cout<<"无公共结点"<<endl;
        }
    
结果
未注释
单链表的第1个值是:1
单链表的第2个值是:8
单链表的第3个值是:9
单链表的第5个值是:5
---------------
单链表的第1个值是:1
单链表的第2个值是:4
单链表的第3个值是:3
单链表的第4个值是:2
单链表的第5个值是:99
单链表的第6个值是:5
公共结点99


注释后
单链表的第1个值是:1
单链表的第2个值是:8
单链表的第3个值是:9
单链表的第4个值是:99
单链表的第5个值是:5
---------------
单链表的第1个值是:1
单链表的第2个值是:4
单链表的第3个值是:3
单链表的第4个值是:2
单链表的第5个值是:5
无公共结点

9

image-20210410124430219

此题暴力解法

和王道 不同,理念一样

代码
void minDel(LinkList &l){
    // int len=length_H(l);比通过长度控制循环要好一点
     while(l->next!=NULL){
        LNode *pre=l->next; //工作指针,指向前一个
        LNode *minpre=l;  //最小元素前一个
         //找到最小的注意 要用next
        while(pre->next!=NULL){
            if(pre->next->data<minpre->next->data){
                minpre=pre;

            }
            pre=pre->next;
        }
        LNode *q=minpre->next;
        int i=1;
        cout<<"第"<<i++<<"个最小的是"<<minpre->next->data<<endl;
        minpre->next=minpre->next->next;
        free(q);
        //len--;


    }
    free(l);

}
演示
 LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,1);
    insertListByOrder_H(l,2,4);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,2);
    insertListByOrder_H(l,5,5);
    printList_H(l);
    // reverse01(l);
    minDel(l);
    cout<<"删除后"<<endl;
    if(isEmpty_H(l)){
        printList_H(l);

    }else{
        cout<<"空"<<endl;
    }
结果
单链表的第1个值是:1
单链表的第2个值是:4
单链表的第3个值是:3
单链表的第4个值是:2
单链表的第5个值是:5
第1个最小的是1
第1个最小的是2
第1个最小的是3
第1个最小的是4
第1个最小的是5
删除后
空

10

image-20210410124445784

代码
//相对位置不变,不能用头插法  
LinkList divide(LinkList &l){
    int i=1;
    LNode *p=l->next; //工作指针
    LinkList B;
    B=(LinkList)malloc(sizeof(LNode));
    B->next=NULL;
    LNode *ra=l;
    LNode *rb=B;
    l->next=NULL;
    while(p!=NULL){
        if(i%2==1){ //奇数
            ra->next=p;
            ra=p;
        }
        if(i%2==0){ //偶数
    
            rb->next=p;
            rb=p;
        }
        p=p->next;
        i++;
    }
    ra->next=NULL;
    rb->next=NULL;
    return B;
}
演示
 LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,1);
    insertListByOrder_H(l,2,2);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,4);
    insertListByOrder_H(l,5,5);
    printList_H(l);  
    cout<<"偶数 2"<<endl;
    printList_H(divide(l));
    cout<<"奇数 l"<<endl;
    printList_H(l);
结果
单链表的第1个值是:1
单链表的第2个值是:2
单链表的第3个值是:3
单链表的第4个值是:4
单链表的第5个值是:5
偶数 2
单链表的第1个值是:2
单链表的第2个值是:4
奇数 l
单链表的第1个值是:1
单链表的第2个值是:3
单链表的第3个值是:5

因为第一个是奇数,下一个若存在,必是偶数所以,可以先奇数操作,再偶数操作

就可以不用判断奇偶数

LinkList divide02(LinkList &l){
    LNode *p=l->next; //工作指针
    LinkList B;
    B=(LinkList)malloc(sizeof(LNode));
    B->next=NULL;
    LNode *ra=l; //尾指针,用于尾插法
    LNode *rb=B; //尾指针
    l->next=NULL;
    while(p!=NULL){      
        ra->next=p;
        ra=p;
        p=p->next;
        if(p!=NULL){
             rb->next=p;
            rb=p;
            p=p->next;
        }      
       
    }
    ra->next=NULL;
    rb->next=NULL;
    return B;
}

11

image-20210410124451092

这题和上面的差不多,唯一区别就是用了头插法

注释掉的部分,是我写的,也可以实现此函数,但没有书上的简练

代码
LinkList divideReverse(LinkList &l){
    LNode *p=l->next;
    l->next=NULL; //可不写,因为最后补充了NULL;
    LinkList B=NULL; 
    B=new LNode; //B头结点 分配空间
    B->next=NULL; //初始化
    LNode *r;//原链表 不断链
    LNode *m=l;//尾插法的尾指针
    /* while(p!=NULL){
        r=p->next;
        //LNode *q=new LNode;
        m->next=p;
        m=p;
        if(r!=NULL){
            p=r->next;
            r->next=B->next;
            B->next=r;
        }        
        else{
            p=p->next;
            }
    } */
    while(p!=NULL){
    m->next=p;
    m=p;
    p=p->next;
    if(p!=NULL){
        r=p->next;
        p->next=B->next;
        B->next=p;
        p=r;
        } 
    }
    m->next=NULL;
    return B;


}

可以通过取消注释的那一行试一下,单数和偶数的不同

演示
 LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,1);
    insertListByOrder_H(l,2,2);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,4);
    insertListByOrder_H(l,5,5);
    //insertListByOrder_H(l,6,6);
    printList_H(l);  
    cout<<"偶数 2"<<endl;
    printList_H(divideReverse(l));
    cout<<"奇数 l"<<endl;
    printList_H(l);
结果
单链表的第1个值是:1
单链表的第2个值是:2
单链表的第3个值是:3
单链表的第4个值是:4
单链表的第5个值是:5
偶数 2
单链表的第1个值是:4
单链表的第2个值是:2
奇数 l
单链表的第1个值是:1
单链表的第2个值是:3
单链表的第3个值是:5

12

image-20210410124459107

感觉我的这段比书上还简单一些

代码
void deleteRepeat(LinkList &l){
    LNode *p=l->next;
    while(p!=NULL){
        LNode *q=p->next;
 //如果p->next即p为空,不做if,继续p=p->next 然后判断为空,跳出循环
        if(q!=NULL && q->data==p->data){ 
            p->next=q->next; 
            free(q);
        }
        p=p->next;
    }
}
演示
	LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,2);
    insertListByOrder_H(l,2,2);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,3);
    insertListByOrder_H(l,5,5);
    //insertListByOrder_H(l,6,6);
    printList_H(l);
    deleteRepeat(l);  
    cout<<"删除重复"<<endl;
    printList_H(l);
结果
单链表的第1个值是:2
单链表的第2个值是:2
单链表的第3个值是:3
单链表的第4个值是:3
单链表的第5个值是:5
删除重复
单链表的第1个值是:2
单链表的第2个值是:3
单链表的第3个值是:5

13

image-20210410124505621

思想是什么???

先依次比较那个比较小,然后头插法.

比较小的那个后移指针

注意循环条件要是两个同时不到NULL

因为长度不同,或者大小的原因,可能有一个先到头了,此时把剩下的元素(最大的,并且有序)依次头插

逻辑相同

最后释放另一个没用到的头结点

注意利用源结点

代码
void combineDesc(LinkList &a,LinkList &b){
    LNode *p=a->next;
    LNode *q=b->next;
    // LNode *qr; //q不断链
    // LNode *pr;  //p不断链
    //优化其实因为两个不会 同时用到,只有一个就行
    LNode *r=NULL;

    a->next=NULL;
    while(p!=NULL && q!=NULL){
        if(p->data<q->data){
            r=p->next;
            p->next=a->next;
            a->next=p;
            p=r;
        }else{
            r=q->next;
            q->next=a->next;
            a->next=q;
            q=r;
        }
    }
    while(p!=NULL){
        r=p->next;
        p->next=a->next;
        a->next=p;
        p=r;

    }
    while(q!=NULL){
        r=q->next;
        q->next=a->next;
        a->next=q;
        q=r;

    }
    //别忘了这句
    free(b);
}
演示
LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,2);
    insertListByOrder_H(l,2,2);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,3);
    insertListByOrder_H(l,5,5);
    insertListByOrder_H(l,6,6);
    printList_H(l);
    cout<<"单链表2"<<endl;
    LinkList l2;
    initList_H(l2);
    insertListByOrder_H(l2,1,1);
    insertListByOrder_H(l2,2,3);
    insertListByOrder_H(l2,3,4);
    insertListByOrder_H(l2,4,9);
    insertListByOrder_H(l2,5,12);
    printList_H(l2);
    combineDesc(l,l2);
    cout<<"合并"<<endl;
    printList_H(l);
结果
单链表的第1个值是:2
单链表的第2个值是:2
单链表的第3个值是:3
单链表的第4个值是:3
单链表的第5个值是:5
单链表的第6个值是:6
单链表2
单链表的第1个值是:1
单链表的第2个值是:3
单链表的第3个值是:4
单链表的第4个值是:9
单链表的第5个值是:12
合并
单链表的第1个值是:12
单链表的第2个值是:9
单链表的第3个值是:6
单链表的第4个值是:5
单链表的第5个值是:4
单链表的第6个值是:3
单链表的第7个值是:3
单链表的第8个值是:3
单链表的第9个值是:2
单链表的第10个值是:2
单链表的第11个值是:1

14

image-20210410124513665

不破坏结点怎么实现??怎们理解??? 也就是新生成是吧

头插法,尾插法,都行

代码
LinkList combineRepeat(LinkList &a,LinkList &b){
    LNode *p=a->next;
    LNode *q=b->next;
    //头结点
    LinkList l;
    l=new LNode;
    //头插法,别忘了置空
    l->next=NULL;
    while(p!=NULL && q!=NULL){
        if(p->data<(q->data)){
            p=p->next;
        }
        else if(p->data>q->data){
            q=q->next;
        }
        else if(p->data==q->data){
            //新结点
            LNode *r=new LNode;
            r->data=p->data;
            p=p->next;
            q=q->next;
            //头插法
            r->next=l->next;
            l->next=r;
        }
    }
    return l;
}
演示
    LinkList l;
    initList_H(l);
    insertListByOrder_H(l,1,2);
    insertListByOrder_H(l,2,2);
    insertListByOrder_H(l,3,3);
    insertListByOrder_H(l,4,3);
    insertListByOrder_H(l,5,5);
    insertListByOrder_H(l,6,6);
    printList_H(l);
    cout<<"单链表2"<<endl;
    LinkList l2;
    initList_H(l2);
    insertListByOrder_H(l2,1,1);
    insertListByOrder_H(l2,2,3);
    insertListByOrder_H(l2,3,4);
    insertListByOrder_H(l2,4,9);
    insertListByOrder_H(l2,5,12);
    printList_H(l2);
    
    cout<<"重复的"<<endl;
    printList_H(combineRepeat(l,l2));
结果
单链表的第1个值是:2
单链表的第2个值是:2
单链表的第3个值是:3
单链表的第4个值是:3
单链表的第5个值是:5
单链表的第6个值是:6
单链表2
单链表的第1个值是:1
单链表的第2个值是:3
单链表的第3个值是:4
单链表的第4个值是:9
单链表的第5个值是:12
重复的
单链表的第1个值是:3
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值