23王道数据结构链表章13-25题总结(伪代码)

13.将两个递增有序的单链表合并成降序的单链表,要求利用原来两个单链表的节点存放归并后的单链表

算法思想:将两个链表中的元素一一比较,使用头插法将结点插入结果表中

LinkList merge_List(LinkList L1,LiskLsit L2){

     LinkList curA = L1->next;
     LInkList curB = L2->next;
     LinkList temp;//保存当前结点的下一个结点,以防断链
        

     curA->next = NULL;//A作结果表
    
     while(curA && curB){

        if(curA->val > curB->val){
            temp = curA->next;
            cueA->next = A->next;
            A->next = curA;
            cueA = temp;
        }else{
            temp = curB->next;
            curB->next = A->next;
            A->next = curB;
            cueB = temp;
           
        }

        
    }

        if(curB){//防止代码冗余,待两段代码逻辑一养的代码
                
            curA = curB;

        }

        while(curB){//如果A或B链表中还有元素
                
             temp = curB->next;
             curB->next = A->next;
             A->next = curB;
             curB = temp;

        }

        free(B);//释放B头节点

        return A;//返回A链表
}

14.设A和B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A和B中的公共元素产生单链表C,注意:要求不破坏A、B的节点

算法思想:遍历A,B链表寻找公共结点,创建新结点复制该公共结点将其尾插到创建的结果表中

LinkList Commom_NodeList(LinkList A,LinkList B){
    
       LinkList curA = A->next;
       LinkList curB = B->next;

       //创建结果表
       LinkList C = (LinkList)malloc(sizeof(ListNode));
       C->next = NULL;
       LinkList rC = C;//尾指针

       while(curA && curB){
            
            if(curA->val > curB->val){

                curB = curB->next;
            }else if(curA->val < curB->val){
                curA = curA->next;

            }else{
                
               /创建新结点进行复制
               LinkList s = (LinkList)malloc(sizeof(ListNode));
               s->val = curA->val;
               
               rC->next = s;
               rC = s;

               curA = curA->next;
               curB = curB->next;
 
            }


       }
        
       rC->next = NULL;
       return C;
}

15.已知两个链表A和B分别表示两个集合,其元素递增排序,编制函数,求A和B的交集,并存放在A链表中,注意要释放其他节点

算法思想:以A作为结果表,将公共结点插入A中,并在遍历的过程中释放其他结点,再释放未遍历完的链表中的结点,最后释放B的头节点

LinkList Commom_List(LinkList A,LinkList B){


        LinkList curA = A->next;
        LinkList curB = B->next;
        LinkList temp;
        
        A->next = NULL;
        LinkList rA = A;

        while(curA && curB){

            if(curA->val > curB->val){
                   temp = curB;
                   curB = curB->next;
                   free(temp);

            }else if(curA->val < curB->val){
                   
                   temp = curA;
                   curA = curA->next;
                   free(curA);

            }else{
                    temp = curB;
                    rA->next = curA;
                    rA = curA;
                    curA = curA->next;
                    curB = curB->next;
                    free(temp);
            }

        }

        if(curB){
            curA = curB;
        }

        while(curA){  //释放没遍历完的链表中的剩余结点
            
            temp = curA;
            curA = curA->next;
            free(temp);

        }        
        
        rA->next = NULL;
        free(B);//释放B的头节点
        return A;

}

16.两个整数序列A=a1,a2,...,an和B=b1,b2,...,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列  

算法思想:朴素的模式匹配

匹配失败:B的长度超出要匹配的A的序列的长度,A先被遍历完

匹配成功:B先被遍历完或A,B同时被遍历完

bool subSet(LinkList A,LinkList B){


    LinkList curA = A->next;
    LinkList curB = B->next;
    LinkList temp = curA;//保存当前A开始比较的结点

    while(curA && curB){

         if(curA->val == curB->val){
    
               curA = curA->next;
               curB = curB->netx;

         }else{
               temp = curA->next;//不相等时,从A的下一个结点开始比较
               curA = temp;
               curB = B->next; //B从头开始
        }

    }

    if(curB == NULL){//若B被遍历完时

        return true;

    }else{

        return false;

    }

}

17.设计一个算法判断带头结点的循环双链表是否对称

算法思想:分别从双链表的头和尾同步相向遍历,直到两个指针相等(奇数个结点)或尾指针的next等于头指针时(偶数个结点)时,遍历过程中的结点值都相同,则对称,否则不对称

bool symmetry(DLinkList L){
    
    LinkList front = L->next;
    LinkList rear = L->prior;

    while(front != rear || rear->next != front){
        
        if(front->val == rear->val){

            front = front->next;
            rear = rear->prior;

        }else{
            return false;
        }

    }

    return true;

}

18.有两个循环单链表,编写一个函数将链表h2连接链表h1之后,要求连接后的链表也是循环单链表

算法思想:遍历链表h1,找到h1的尾结点,将h2尾插到h1后,再遍历h2,找到h2的尾结点,将其链接到h1的头节点上

LinkList Link_List(LinkList h1,LinkList h2){


       if(h1 == NULL){
            return h2;
        }else{
            return h1;
        }

        LinkList head = h1;

        while(h1->next){//找h1的尾结点
            h1 = h1->next;
        }

        h1->next = h2;

        while(h2->next){//找h2的尾结点
            h2 = h2->next;
        }

        h2->next = head;

}

19.设有一个带头结点的循环单链表,其节点值为正整数,设计一个算法,反复找出单链表中节点值最小的节点并输出,然后将该节点从中删除,直到单链表为空为止,在删除表头节点

算法思想:解法和代码同第9题

void Del_minNode(LinkList L){

    LinkList p,pre,temp;

    while(L->next != L){//循环至只剩头结点

        p = L->next;//初始时假设当前链表中第一个结点是最小的
        pre = L;//pre始终指向最小结点的前驱结点
    
        //找最小结点
        while(p->next && pre->next->val > p->next->val){  

            pre = p;
            p = p->next;
  
        }
        
        //输出并删除最小结点
        print(pre->next->val);
        temp = pre->next;
        pre->next = pre->next->next;
        free(temp);

    }

    free(L);//释放头节点

}

20.非循环双向链表L有头节点,有一个访问频度阈freq,初值为0,链表每进行一次Locate(L,x),值为x的节点的频度就加1,并且让节点保持按访问频度非增(递减)的顺序排列,同时最近访问的节点排在频度相同节点的前面,以便让频繁访问的节点靠近表头,试编写符合以上要求的Locate(L,x)运算的算法,返回找到节点的地址,类型为指针型元素值唯一

算法思想:查找该结点使其频度加1,并从当前位置删除该结点,按照频度大小查找该结点的插入位置并插入该结点,使其链表按频度递减

LinkList Locate(LinkList L,ElemType x){

        LinkList cur = L->next;
        LinkList pre;

        while(cur){
            
            if(cur->val == x){
                
                cur->fraq++;//访问频度加1
                pre = cur->prior;//保存其前驱结点,以便删除

                //从当前位置删除
                if(cur->next){//如果cur的下个结点不为空
                    cur->next->prior = pre;
                }
                pre->next = cur->next;

                break;//跳出循环

            }else{

                cur = cur->next;

            }

        }


        if(cur == NULL){//查找失败,链表中不存在x
            return NULL;
        }

        //查找插入位置,pre指向其前驱结点
        while(pre != L && pre->fraq <= cur->fraq){

            pre = pre->prior;

        }
        
        //插入操作
        cur->next = pre->next;

        if(pre->next){
             pre->next->prior = cur;
        }
       
        cur->prior = pre;
        pre->next = cur;

        return cur;

}

21.判断单链表是否有环

算法思想:Floyd判圈算法(龟兔赛跑算法)

快慢指针 :快指针一次走两步,慢指针一次走一步,如果链表中有环,快指针先进入环,慢指针进入环后,必在某一时刻,快慢指针相遇,如果无环,慢指针必将追不上快指针,而快指针先遍历结束

bool is_Circle(LinkList L){
    
    LinkList slow = L;
    Linklist fast = L;

    while(fast && fast->next){

        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow){
            return true;
        }
    
    }

    return false;

}

22.寻找链表倒数第k个结点

算法思想:定义两个指针,使第一个指针先遍历k次,之后两个指针再同步遍历,当第一个指针遍历到最后一个结点时,第二个指针指向倒数第k个结点。

​
int revese_k(LinkList list,int k){

    if(!list || k == 0){
        return 0;
    }

    LinkList cur = list->next;
    LinkList pre = L->next;

    while(k--){

        cur = cur->next;
    }

    while(cur){

        pre = pre->next;
        cur = cur->next;

    }
    
    print(pre->val)
    return 1;

}

​

23.找相交链表的第一个起始节点

算法思想:解法和代码同第8题

24.删除绝对值相等的节点,只保留靠近头结点的节点,结点的绝对值<=n

算法思想:申请一个数组空间,各结点的值作为数组下标,当初次访问某一结点的绝对值时,其数组元素设为1,代表已有该结点值,当访问到某一结点时,对应数组元素为1,即是绝对值相等的结点,删除该结点


void Delete_Node(LinkList head){

    if(!head->next){
        return;
    }
    
    //创建并初始化数组
    int* arr = (int*)malloc(sizeof(int)*n+1);
    for(int i = 0;i < n+1;i++){
        arr[i] = 0;
    }

    LinkList cur = L->next,pre = L;//pre指向cur的前驱结点,以便删除
   
    whiile(cur){

        if(arr[abs(cur->val)] != 1){//初次访问该绝对值元素,保留该结点,并设置访问标记
            arr[abs(cur->val)] = 1;
            pre = cur;
            cur = cur->next;
        }else{//绝对值相等的结点,删除
            pre->next = cur->next;
            free(cur);
            cur = pre->next;
        }

    }

    free(arr);//释放数组

}

​

25.设线性表L={a1,a2,a3,...,an-2,an-1,an}采用带有头结点的单链表保存,设计一个空间复杂度为o(1)且时间尽可能高效的算法,重新排列L中的各结点,得到L'={a1,an,a2,an-1,a3,an-2,...}

算法思想:先用快慢指针找到中间结点,将第二条链表反转后,再将第二条链表逐个间隔插入第一条链表中

LinkList Revese_List(LinkList L){//反转链表

     LinkList cur = L->next;
     LinkList pre = L;
     L->next = NULL;
     LinkList temp;

     while(cur){
    
        temp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = temp;
        
    }

    return pre;

}

//快慢指针找到中间结点(偶数个结点时中间结点为第二个结点)
LinkList midNode(LinkList L){
    
    LinkList slow = L;
    LinkList fast = L;

    while(fast && fast->next){
        
        fast = fast->next->next;
        slow = slow->next;

    }

    return slow;

}


void Set_List(LinkList L){

    if(!L->next){
        return;
    }


    LinkList SecondListStartNode = midNode(L->next);
    LinkList SecondListHead = Revese_List(SecondListStartNode);

    LinkList cur = SecondListHead;
    LinkList pre = L->next;//指向插入位置的前驱结点
    LinkList temp1;//保存cur的下一个结点,以防断链
    LinkList temp2;//保存下一个插入位置的前驱结点

    while(cur){

        temp1 = cur->next;
        temp2 = pre->next;
      
        cur->next = pre->next;
        pre->next = cur;
        
        cur = temp1;
        pre = temp2;

    }

    
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值