链表相关经典算法题总结(C语言+数据结构)

我们针对链表中最经典的几道算法题做讲解:

1.求两个链表的公共节点.

2.判断链表是否有环.

3.给定一个链表,判断是否有环,有返回入环的第一个节点,无返回空.(在第二题上的加强版).

4.给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝.

5.对链表进行插入排序.

6.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针.

一.详细讲解

1.求两个链表的公共节点.(如图)

typedef struct ListNode node;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    node* cur1=headA;
    node* cur2=headB;
    int sum1=0;
    int sum2=0;
    int before=0;
    while(cur1->next){//判断第一个节点的长度,并走到最后一个节点
        cur1=cur1->next;
        sum1++;
    }
    while(cur2->next){//判断第二个节点的长度,并走到最后一个节点
        cur2=cur2->next;
        sum2++;
    }
    if(cur1!=cur2){//判断最后一个节点是否相等,相等则有公共节点,不相等则没有直接返回.
        return NULL;
    }
    if(sum1>sum2){//判断两个链表那个长,长的那个先走,直到两个距离最后一个节点相同距离.
        before=sum1-sum2;
        for(int i=0;i<before;i++){
            headA=headA->next;
        }
    }
    if(sum2>sum1){//同上
        before=sum2-sum1;
        for(int i=0;i<before;i++){
            headB=headB->next;
        }
    }
    while(headA!=headB){//两个同时向后走当其相等时,这个节点就是公共节点.
        headA=headA->next;
        headB=headB->next;
    }
    return headA;
}

2.判断链表是否有环(如图).

typedef struct ListNode node;
bool hasCycle(struct ListNode *head) {
    if(NULL==head || NULL==head->next){//判空
        return false;
    }
    node* slow=head;//定义两个快慢指针
    node* fast=head;
    int temp=0;
    while(1){//快指针每次走两步,慢指针每次走一步.
        slow=slow->next;
        fast=fast->next->next;
        if(NULL==fast || NULL==fast->next){//如果可以走到尾部说明无环.
            temp=1;
            break;
        }
        if(slow==fast){//如果快慢指针相遇说明有环.
            break;
        }
    }
    if(1==temp){
        return false;
    }else{
        return true;
    }
}

3.给定一个链表,判断是否有环,有返回入环的第一个节点,无返回空.(在第二题上的加强版)(如图).

typedef struct ListNode node;
struct ListNode *detectCycle(struct ListNode *head) {
   node* slow=head;
   node* fast=head;
   int temp=0;
   while(fast!=NULL && fast->next!=NULL){//同上,定义快慢指针判断是否有环.
       slow=slow->next;
       fast=fast->next->next;
       if(slow==fast){
           temp=1;
           break;
       }
   } 
   if(0==temp){//temp为0说明没环,直接返回.
       return NULL;
   }
   node* head2=fast;
   while(head2 != head){//有环同时向后走,相遇时便是入环点.
       head=head->next;
       head2=head2->next;
   }
   return head2;
}

4.给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝.

https://blog.csdn.net/weixin_49312527/article/details/121598778?spm=1001.2014.3001.5501

5.对链表进行插入排序.

a.定义一个新的空节点,将链表中的第一个直接连到这个空节点上,然后后面的节点依次与新节点后面的节点比较,比其大就向后走,继续比较,如果走到最后则直接连到最后一个节点上,如果比其小则直接连到其前面.等到全部连完,返回新节点的next就是插入排序后的节点的头节点.

typedef struct ListNode Node;
struct ListNode* insertionSortList(struct ListNode* head){
    if(NULL==head||NULL==head->next){//判空
        return head;
    }   
    Node* no_head=(Node*)malloc(sizeof(Node));
    no_head->next=head;
    Node* cur=head->next;
    head->next=NULL;
    Node* Next=NULL;
    Node* new_head=NULL;
    while(cur!=NULL){//定义一个新的空节点,将链表中的第一个直接连到这个空节点上,然后后面的
//节点依次与新节点后面的节点比较,比其大就向后走,继续比较,如果走到最后则直接连到最后一个节点
//上,如果比其小则直接连到其前面.等到全部连完,返回新节点的next就是插入排序后的节点的头节点.
        Next=cur->next;
        cur->next=NULL;
        new_head=no_head;
        while(new_head->next!=NULL){
            if(new_head->next->val<cur->val){
                new_head=new_head->next;
            }else{
                break;
            }
        }
        cur->next=new_head->next;
        new_head->next=cur;
        cur=Next;
    }
    return no_head->next;
}

6.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针.

a.首先定义一个空的头节点连接在该链表前,让prv处在no_head(空的头节点),cur处在head(源头节点),如果cur节点不是尾节点,并且与其后面的节点相等,就进入循环一直向后走,找到不相等的节点是结束循环,prv直接连在这,跳过所的相等节点,cur继续放在prv的next处,进行循环判断.如果cur与其后面的不相等,prv和cur同时向后走继续循环判断.

typedef struct ListNode Node;
struct ListNode* deleteDuplication(struct ListNode* pHead ) {
    if(NULL==pHead  || NULL==pHead->next){
        return pHead;
    }
    Node* no_head=(Node*)malloc(sizeof(Node));
    no_head->next=pHead;
    Node* prev=no_head;
    Node* cur=pHead;
//首先定义一个空的头节点连接在该链表前,让prv处在no_head(空的头节点),cur处在head(源头节点),
//如果cur节点不是尾节点,并
//且与其后面的节点相等,就进入循环一直向后走,找到不相等的节点是结束循环,prv直接连在这,跳过所的
//相等节点,cur继续放在prv的next处,进行循环判断.如果cur与其后面的不相等,prv和cur同时向后走继续
//循环判断.
    while(NULL!=cur){
        if(cur->next!=NULL && cur->val==cur->next->val){
            while(cur->next!=NULL && cur->val==cur->next->val){
                cur=cur->next;
            }
            prev->next=cur->next;
            cur=cur->next;
        }else{
            prev=prev->next;
            cur=cur->next;
        }
    }
    return no_head->next;
}

猜你喜欢

转载自blog.csdn.net/weixin_49312527/article/details/121892690
今日推荐