链表的应用

在面试中,关于链表的考察,大多都是结合题目来对链表进行综合考察。链表的一些应用一般为以下几种。


  • 单链表反转
  • 链表中环的检测
  • 两个有序的链表合并
  • 删除链表倒数第n个节点
  • 求删除的中间节点
  • 两两交换链表中的节点

单链表反转

		//解法一 
    struct ListNode* reverseList(struct ListNode* head) {
    	//定义三个指针 
	    struct ListNode *nodePre,*nodeCur,*nodeNext;
	    
	    //为三个指针开辟空间 
	    nodePre = (struct ListNode*)malloc(sizeof(struct ListNode) * 1);
	    nodeCur = (struct ListNode*)malloc(sizeof(struct ListNode) * 1);
	    nodeNext = (struct ListNode*)malloc(sizeof(struct ListNode) * 1);
	    
	    //如果链表为空或者只有一个节点,直接返回head 
	    if(head == NULL || head->next == NULL)
	    	return head;
	    
	    //将pre,cur,next分别指向链表的第一、第二和第三个节点 
	    nodePre = head;
	    nodeCur = head->next;
	    nodeNext = nodeCur->next;
	    
	    //当前节点不为空 
	    while(nodeCur)
	    {
	    	//当前节点的下一个节点变为前一个节点 
	    	nodeCur->next = nodePre;
	    	//将第一、第二个节点往后移 
	    	nodePre = nodeCur;
	    	nodeCur = nodeNext;
	    	//如果第三个节点不为空,就往后移 
	    	if(nodeNext)
	    		nodeNext = nodeNext->next;
	    	}
	    	
	    	//此时反转完成,head节点为最后一个节点 
	    	head->next = NULL;
	    	//将头节点指向最后一个节点 
	    	head = nodePre;
	    	return head;
    }
    
    //解法一 
    struct ListNode* reverseList(struct ListNode* head) {
    	//将前一个节点置为空,当前节点指向头节点 
       struct ListNode *prev = NULL,*cur = head;
       
       //当当前节点不为空时 
       while(cur)
       {
       		//nextNode指向当前节点的下一个节点 
    		ListNode *nextNode = cur->next;
    		//当前节点的下一个节点指向上一个节点 
    		cur->next = prev;
    		//将当前节点和前一个节点都往后移 
    		prev = cur;
    		cur = nextNode;
       }
       return prev;
    }
    

链表中环的检测

//给定一个链表,判断链表中是否有环 
bool hasCycle(struct ListNode *head) {
	//定义快慢指针 
	struct ListNode *slow,*fast;
	//初始将快慢指针都指向头节点 
	slow = head;
	fast = head;
	
	//当慢节点不为空且指针的下一个不为空时
	//(因为里面要执行快指针走两步,所以要判断快指针的下一个不为空) 
	while(slow != NULL && fast->next != NULL){
		
		//快指针走两步,慢指针走一步 
		slow = slow->next;
		fast = fast->next->next;
		
		//如果快指针等于慢指针,说明存在换 
		if(slow == fast)
			return true;
		//如果快指针等于空,说明不存在环 
		if(fast == NULL)
			return false;
	}
	return false;
}

两个有序的链表合并

//合并两个链表,并将合并后的链表返回 
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    
	//如果l1链表为空,就返回l2链表 
    if(!l1)
		return l2;
	//如果l2为空,返回l1 
	if(!l2)
		return l1;
		
	//创建一个新节点,并指向空 
	struct ListNode *newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
	newNode = NULL;
	
	//如果l1节点的值小于等于l2节点的值 
	if(l1->val <= l2->val){
		//新节点指向l1 
		newNode = l1;
		//新节点的下一个节点指向递归返回的值(因为此函数一直在做的就是找到两个对应的值,哪个最小) 
		newNode->next = mergeTwoLists(l1->next,l2);
	}else{
		//否则新节点指向l2 
		newNode = l2;
		newNode->next = mergeTwoLists(l1,l2->next);
	}
    return newNode;
        
}

删除链表倒数第n个节点

//给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
	
	//创建哨兵(防止对头节点进行处理时出错) 
    struct ListNode *dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
    //哨兵节点的下一个节点定义为头节点 
    dummy->next = head;
    
    //定义慢节点和快节点,并指向哨兵 
    struct ListNode *slowNode = dummy;
	struct ListNode *fastNode = dummy;
    
    //当快节点的下一个节点不为空时 
    while(fastNode->next != NULL)
    {
    	//当n<=0时,往后移动慢节点 
    	if(n<=0)
    		slowNode = slowNode->next;
    	//移动快节点 
    	fastNode = fastNode->next;
    	//每次n-- 
    	n--;
	}
	
	//当慢节点的下一个节点不为空时 
	if(slowNode->next != NULL)
		//慢节点的下一个节点指向下下个节点,下个节点即为要删除的节点 
		slowNode->next = slowNode->next->next;
	//返回哨兵的下一个节点,即头节点 
    return dummy->next;
}

求删除的中间节点

//给定一个带有头结点 head 的非空单链表,返回链表的中间结点
struct ListNode* middleNode(struct ListNode* head) {
	
	//定义防止哨兵节点(防止对头节点进行处理时出错) 
	struct ListNode *dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
	//将哨兵节点的下一个节点指向头节点 
	dummy->next = head;
	
	//统计链表的长度 
    int length = 0;
    
    //利用哨兵节点统计链表的长度 
    while(dummy->next != NULL)
    {
    	dummy->next = dummy->next->next;
    	length++;
	}
	
	//求出链表的中间位置 
	length /= 2;
	//将哨兵节点重新指向头节点 
	dummy->next = head;
	//利用链表的中间位置索引,求出链表的中间的指针 
	while(length--)
		dummy->next = dummy->next->next;
	return dummy->next;
    
}

//解法二 
struct ListNode* middleNode(struct ListNode* head) {
	
	//设置快慢节点 
    struct ListNode *slow,*fast;
    //将快慢节点都指向头节点 
	slow = head;
	fast = head;
	
	//当慢节点不为空并且快节点的下一个节点不为空
	//(因为要使用要快节点的下下个节点,所以要确保快节点的下一个节点不为空) 
	while(fast != NULL && fast->next != NULL){
		//慢节点移动一次,快节点移动两次 
		slow = slow->next;
		fast = fast->next->next;
	}
	
	return slow;
}

两两交换链表中的节点


//给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
struct ListNode* swapPairs(struct ListNode* head) {

    //如果链表为空表或者只有一个节点,就直接返回 
    if(!head || !head->next)
    	return head;
    //定义临时节点tmp,并且指向头节点的下一个节点 
    struct ListNode *temp = head->next;
    //头节点的下一个节点指向后面一组两两交换后的地址 
    head->next = swapPairs(temp->next);
    //第二个节点的下一个节点指向头节点 
    temp->next = head;
    return temp;
}

代码(题目链接):

https://github.com/Han-YLun/DataStructureAndAlgorithm

总结:

很多人也许一看到链表为头疼,但是链表是我们学习和掌握数据结构跨不过去的坎。我们只有多加练习,了解链表真正的含义,才能真正的掌握。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值