链表——单链表常见的五种操作

五种常见操作

以下代码都是针对引入哨兵的带头链表

1、单链表反转

原地反转

	public static Node reverseLinkList(Node head){
		if(head.next == null){
			return head;
		}
		Node prev = head.next;
		Node pcur = prev.next;
		while(pcur != null){
			prev.next = pcur.next;
			pcur.next = head.next;
			head.next = pcur;
			pcur = prev.next;
		}
		return head;
	}

头插法反转

	public static Node reverseLinkList(Node head){
		if(head.next == null){
			return head;
		}
		Node newHead = new Node();
		Node pcur = head.next;
	    Node curNextTmp = null;
		while(pcur != null){
			curNextTmp = pcur.next;
			pcur.next = newHead.next;
			newHead.next = pcur;
			pcur = curNextTmp;
		}
		return newHead;
	}

2、链表中环检测

快慢指针法

  • 两个指针同时从第一个数据节点开始,pFast每次移到两个节点,pSlow每次移到一个节点
  • pFast先到尾部即pFast == null,说明没有闭环
  • 如果有闭环 则最终两个指针会相遇即 pFast==pSlow
    public static boolean hasLoop(Node head){
        if(head.next==null){
            return false;
        }
        Node pFast = head.next;
        Node pSlow = head.next;
        while (pFast!=null&&pSlow!=null){
            pFast = pFast.next.next;
            pSlow = pSlow.next;
            if(pFast==null){
                //这个判断不能少,否则可能会陷入死循环
                return false;
            }else if(pFast==pSlow){
                return true;
            }
        }
        return false;
    }

3、两个有序链表合并

递归

  • 递归代码简洁,不递归通过迭代也可以通过两个指针遍历解决;
	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null&&l2==null){
            return null;
        }else if(l1==null){
            return l2;
        }else if(l2==null){
            return l1;
        }
        //递归
        ListNode l3;
        if(l1.val > l2.val){
            l3=l2;
            l3.next=mergeTwoLists(l1,l2.next);
        }else{
            l3=l1;
            l3.next=mergeTwoLists(l1.next,l2);
        }
        return l3;
        
        //迭代
        /*ListNode head = new ListNode(-1);
        ListNode pcur = head;
        while(l1!=null && l2!=null){
            if(l1.val<=l2.val){
                pcur.next = l1;
                l1 = l1.next;
            }else{
                pcur.next = l2;
                l2 = l2.next;
            }
            pcur = pcur.next;
        }
        pcur.next = l1==null?l2:l1;
        return head.next;*/

    }

4、删除链表倒数第 n 个节点

快慢指针法

  • 让fast指针先移动n个节点之后slow节点再加入一起向后移动,直至fast==null,此时slow指向的就时倒是第N个;
  • 链表为空或者n小于0或者超出链表长度返回null;
	public static Node removeNthFromEnd(Node head,int n){
        if(head.next==null || n<=0){
            return head;
        }
        //fast和slow都指向哨兵
        Node fast = head;
        Node slow = head;
        int count = 0;
        //循环结束条件要注意时fast.next!=null
        //如果时fast!=null,则n=1的时候会出问题
        //注意边界条件
        while (fast.next!=null){
            if(count<n){
                //这里至少会执行一次
                fast = fast.next;
                count++;
            }else{
                fast = fast.next;
                slow = slow.next;
            }
        }
        slow.next = slow.next.next;
        return head;
    }

5、求链表的中间节点

快慢指针法

  • fast每次移动两个节点,slow每次移动一个节点同时向尾部移动,fast.next==null时结束,此时slow指向中间节点
	public static Node middleNode(Node head) {
        if (head.next == null) {
            return head;
        }
        Node slow = head;
        Node fast = head;
        //长度可能为奇数和偶数,奇数结束fast==null,偶数结束fast.next==null
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

熄灯

以上代码链表都是引入哨兵的带头链表

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
链表的基本操作: 2.链表的基本操作链表施行的操作有很多种,最基本的操作是在链表中插入结点、在链表中删除结点、在链表中查找结点等。 (1) 链表结点的插入 ①在空链表中插入一个结点 空链表就是头指针为空的链表。 a)用如下语句申请一个new结点: new=(struct node)calloc(1,sizeof(struct node)); b)为new结点填充数据:将要存储的数据对应传递给new结点数据域的各个成员。 c)修改有关指针的指向:将new的next成员置空,使new结点成为链表的最后一个结点;将head指向new结点。 ②在链表的结点之后插入一个结点 要在链表head的C、D结点之间出入一个new结点,就是将new结点变成C结点的下一个结点,而new结点的下一个结点为D结点. 操作过程为: a) 使new的指针域存储结点D的首地址。 b) 使C结点的指针域存储结点new的地址。 例2 建立学生成绩链表链表有3个结点。 #include <stdio.h> #define N 3 struct s_node { char num[4]; int score; struct s_node *next; }; main() { struct s_node *creat_node(void); /*生成链表结点的函数*/ struct s_node *creat_list(int n); /*建立链表的函数*/ void out_list(struct s_node *head); /*输出链表函数*/ struct s_node *head=NULL; head=creat_list(N); out_list(head); } struct s_node *creat_node(void) /*生成链表结点的函数*/ { struct s_node *p; int score; fflush(stdin); p=(struct s_node *)calloc(1,sizeof(struct s_node)); gets(p->num); scanf("%d",&score); p->score=score; ........

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小技工丨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值