数据结构例题(链表) ---猛男专属

目录

*链表数据结构例题

1.输入两个链表,找出它们的第一个公共结点:

 2.给定一个链表,判断链表中是否有环

3.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL.

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

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

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


*链表数据结构例题

1.输入两个链表,找出它们的第一个公共结点:

题目:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

分析:1.先判断链表是否相交:

            设置两个指针遍历两个链表,如果最后的节点地址相同则相交;

            不相交则返回NULL;

        2.相交则判断交点位置:

                a求两个链表的长度n1和n2;

                b.判断n1,n2的长度差k(长的减短的)

                c.让长的先走k步,然后两个指针同时开始走,地址相等的第一个交点为两个链表的交点

         3.   返回交点地址;

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 int Judje(struct ListNode *headA, struct ListNode *headB){//判断链表是否相交
     if(headA==NULL||headB==NULL){
         return 0;
     }
    struct ListNode* cur1=headA;
    struct ListNode* cur2=headB;
     while(cur1){
         cur1=cur1->next;
     }
     while(cur2){
         cur2=cur2->next;
     }
     if(cur1==cur2){
         return 1;
     }else{
         return 0;
     }
 }
 int NodeSize(struct ListNode * head){//获取链表的长度
     if(head==NULL){
         return 0;
     }
     int count=0;
     struct ListNode * cur=head;
     while(cur){
         cur=cur->next;
         count++;
     }
     return count;
 }
 struct ListNode * getnode(struct ListNode * headA,struct ListNode * headB){//获取链表的公共节点
     struct ListNode * cur1=headA;
     struct ListNode * cur2=headB;
     while(cur1&&cur2){
         if(cur1==cur2){
             return cur1;
         }else{
             cur1=cur1->next;
             cur2=cur2->next;
         }
     }
     return NULL;
 }
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL&&headB==NULL){
        return NULL;
    }
    int sizeA=NodeSize(headA);
    int sizeB=NodeSize(headB);
    if(Judje(headA,headB)){//如果有交点进循环
        if(sizeA>sizeB){//让长的链表先走k
            int k=sizeA-sizeB;
            while(k--){
                headA=headA->next;
            }
        }
        else{
             int k=sizeB-sizeA;
            while(k--){
                headB=headB->next;
            }
        }
        return getnode(headA,headB);//找公共节点
    }  
    return NULL;//如果没有交点返回NULL
}

 2.给定一个链表,判断链表中是否有环

题目:

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

解析:判断链表是否有环非常简单:

1.使用两个指针:fast    slow

2.fast每次走两步,slow每次走一步.

3.如果fast&&fast存在并且在循环中fast==slow则存在环,若循环出来则不存在环

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* fast=head;//快指针一次走两步
    struct ListNode* slow=head;//慢指针一次走一步
    if(head==NULL){
        return NULL;
    }
    while(fast&&fast->next){
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow){//如果快慢指针相遇则有环
            return true;
        }
    }
    return false; //快指针走到NULL则没有环
}

3.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL.

题目:

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表.

解析:

1.首先判断是否带环(参考2)

2.带环则判断第一个交点:

        a.找到一个环内元素

        b.让一个指针从这个元素开始顺序走,然后同时一个指针从头开始走

        c.相遇的时候就是所求节点(如图):

   设环长度为R,第一次交点为如图,

由题可知:   fast: L+nR+X

                   slow:L+X

******fast一次走两步.slow一次一步

则有:2*(L+X)==L+nR+X

化简可得:L+X==nR.------>L==R-X

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 struct ListNode* Judecircul(struct ListNode* head){//判断是否带环
     if(head==NULL){
         return NULL;
     }
     struct ListNode* fast=head;
     struct ListNode* slow=head;
     while(fast&&fast->next){
         fast=fast->next->next;
         slow=slow->next;
         if(fast==slow){
             return fast;
         }
     }
     return NULL;
 }
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* cur=head;//指针从头开始
    if(head==NULL){
        return NULL;
    }
    struct ListNode* p=Judecircul(head);
    if(p==NULL){//如果不带环直接返回NULL;
        return NULL;
    }else{
        while(p!=cur){//求交点
            p=p->next;
            cur=cur->next;
        }
        return cur;//返回交点
    }  
}

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

题目:

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
你的代码 只 接受原链表的头节点 head 作为传入参数

解析:

1.首先在每个节点后面插入一个和此节点相同的节点

2.复制新节点的random域

3.还原链表并返回复制链表的地址

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
    if(head==NULL){
        return NULL;
    }
     struct Node* cur=head;
    //1.复制原结点
    while(cur){
        struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
        newnode->val=cur->val;

        newnode->next=cur->next;
        cur->next=newnode;
        cur=newnode->next;
    }
    //2.复制结点的random域
    cur=head;
    while(cur){
        struct Node* prev=cur->next;
        if(cur->random==NULL){
        prev->random=NULL;
        }
        else{
        prev->random=cur->random->next;
        }
        cur=prev->next;
    }
     //3.断开链表 
    cur = head;
    struct Node* back = head;
    struct Node* newhead = cur->next;
    struct Node* front = NULL;
    while (back->next) {
        front = back->next;
        back->next = front->next;
        back = front;
    }
    return newhead;
}

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

题目:

1.插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
2.每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
3.重复直到所有输入数据插入完为止。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4
示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

解析:

a.先加一个头节点以便于从头开始比较

b.设置两个指针(cur,prev)和一个中间变量指针(tmp),prev在前,cur在后

c.判断cur和prev的val的大小,如果cur小则继续遍历,反之用tmp指向开始节点并比较(寻找插入位置)

d.插入节点并继续遍历

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* insertionSortList(struct ListNode* head){
    if(head==NULL){
        return NULL;
    }
    struct ListNode* Head=(struct ListNode*)malloc(sizeof(struct ListNode));
    Head->next=head;//加一个头节点
    struct ListNode* cur=head->next;
    struct ListNode* prev=head;
    struct ListNode* tmp;
    while(cur){
        if(cur->val>prev->val){//后面的大不需要排序
            prev=prev->next;
            cur=cur->next;
        }else{//后面的小
           tmp=Head;
           while(cur->val>tmp->next->val){//寻找插入位置
               tmp=tmp->next;
           }
           prev->next=cur->next;//进行插入
           cur->next=tmp->next;
           tmp->next=cur;
           cur=prev->next;
        }
    }
return Head->next;//返回头节点的next

}

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

题目:

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5  处理后为 1->2->5

数据范围:链表长度满足  1<=n<=1000,链表中的值满足 1<=val<=1000

例如输入{1,2,3,3,4,4,5}时,对应的输出为{1,2,5},对应的输入输出链表如下图所示:

 

解析:

a.首先申请一个头节点便于操作

b.设置两指针cur和prev,cur指向申请的头,prev指向原来的头

c.遍历链表,判断cur和prev的val是否相等,相等的话再判断有几个相等的,直到cur到不相等的节点

d.删除中间相等的节点

e.返回申请节点的next

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param pHead ListNode类 
 * @return ListNode类
 */
struct ListNode* deleteDuplication(struct ListNode* pHead ) {
    // write code here
    //如果为空链表返回空
    if(pHead==NULL){
        return NULL;
    }
    //申请头节点
    struct ListNode* Head=(struct ListNode*)malloc(sizeof(struct ListNode));
    Head->next=pHead;
    struct ListNode* cur=pHead;
    struct ListNode* prev=Head;
    while(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 Head->next;// 返回头节点的next
}

 1~5题转自力扣,6转自牛客

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值