版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1135004584/article/details/79326741
腾讯面试题:如何快速查找指定链表的中间节点?
解法1:遍历法。
先遍历一遍统计链表长度,然后再遍历长度的1/2便即是中间节点。
时间复杂度O(3n/2)
解法2:快慢指针。(推荐)
设置两个指向链表头结点的指针,一个指针的遍历速度是另一个指针的2倍,当快的指针遍历完毕,慢指针即是中间节点。
时间复杂度O(n/2)
解法二比解法一速度快了足足3倍,可见算法的威力。
解法二代码:
LinkList.h
#ifndef _LINK_LIST_H_ #define _LINK_LIST_H_ #include <stdbool.h> struct Node{ int key; int value; struct Node * next; struct Node * previous; }; typedef struct linkList{ int length; struct Node * item; }LinkList; //初始化链表 void initLinkList(LinkList * pLinkList); //销毁链表 void destroyLinkList(LinkList * pLinkList); //在链表尾部添加节点 bool addNode(LinkList * pLinkList,struct Node * node); //在指定位置插入节点 bool insertNode(LinkList * pLinkList,struct Node * node,int pos); //通过key移除指定节点 bool removeById(LinkList * pLinkList,int key); //通过key修改指定节点的value bool updateById(LinkList * pLinkList,int key,int value); //通过key查找指定节点 struct Node * findByKey(LinkList * pLinkList,int key); //将每个函数应用于节点 void Traverse(LinkList * pLinkList,void (*pfun)(struct Node * node)); //判断位置是否在链表范围内 bool isObtains(LinkList * pLinkList,int pos); //key所在节点是否存在 bool isExistKey(LinkList * pLinkList,int key); #endif
LinkList.c
#include <stdbool.h> #include <stdlib.h> #include "LinkList.h" //初始化链表 void initLinkList(LinkList * pLinkList) { pLinkList->length = 0; pLinkList->item = NULL; } //销毁链表 void destroyLinkList(LinkList * pLinkList) { pLinkList->length = 0; struct Node * node = pLinkList->item; struct Node * nTemp; while(node) { nTemp = node; node = node->next; free(nTemp); } pLinkList->item = NULL; } //在链表尾部添加节点 bool addNode(LinkList * pLinkList, struct Node * node) { if(pLinkList->item && node) { struct Node * n = pLinkList->item; while(n->next) { n = n->next; } n->next = node; pLinkList->length++; return true; } else if(!pLinkList->item && node) { pLinkList->item = node; pLinkList->length++; return true; } return false; } //在指定位置插入节点 bool insertNode(LinkList * pLinkList,struct Node * node,int pos) { if(isObtains(pLinkList,pos)) { int j=0; struct Node * n = pLinkList->item; while(n && j<pos) { j++; n = n->next; } if(n) { node->previous = n; node->next = n->next; n->next = node; pLinkList->length++; return true; } } return false; } //通过key移除指定节点 bool removeById(LinkList * pLinkList,int key) { struct Node * node = pLinkList->item; if(node->key == key) { pLinkList->item = node->next; free(node); return true; } struct Node * pNTemp; while(node->next) { if(node->next->key == key) { pNTemp = node->next; node->next = node->next->next; free(pNTemp); return true; } node = node->next; } return false; } //通过key修改指定节点的value bool updateById(LinkList * pLinkList,int key,int value) { struct Node * node = findByKey(pLinkList,key); if(node) { node->value = value; return true; } return false; } //通过key查找指定节点 struct Node * findByKey(LinkList * pLinkList,int key) { struct Node * node = pLinkList->item; while(node) { if(node->key == key) { return node; } node = node->next; } return NULL; } //将每个函数应用于节点 void Traverse(LinkList * pLinkList,void (*pfun)(struct Node * node)) { struct Node * node = pLinkList->item; while(node) { (*pfun)(node); node = node->next; } } bool isObtains(LinkList * pLinkList,int pos) { if(pLinkList->item && pLinkList->length>0 && pos>=0 && pLinkList->length>pos) return true; else return false; } bool isExistKey(LinkList *pLinkList, int key) { struct Node * node = pLinkList->item; while(node) { if(node->key == key) { return true; } node = node->next; } return false; }
main3.c
#include "LinkList.h" #include <stdio.h> /** * function:利用快慢指针快速找到指定链表的中间节点 * description: * 通过遍历查找指定链表的中间节点时间复杂度O(3n/2) * 通过快慢指针查找指定链表的中间节点时间复杂度O(n/2) * 效率提高了3倍 */ struct Node * findHalf(LinkList * l1) ; int main(void) { LinkList linkList1; initLinkList(&linkList1); struct Node n1,n2,n3; n1.value = 1; n1.next = NULL; n2.value = 2; n2.next = NULL; n3.value = 3; n3.next = NULL; addNode(&linkList1,&n1); addNode(&linkList1,&n2); addNode(&linkList1,&n3); struct Node * n4 = findHalf(&linkList1); printf("value = %d\n",n4->value); return 0; } /** * function:利用快慢指针快速找到指定链表的中间节点 * description: * 通过遍历查找指定链表的中间节点时间复杂度O(3n/2) * 通过快慢指针查找指定链表的中间节点时间复杂度O(n/2) * 效率提高了3倍 */ struct Node * findHalf(LinkList * l1) { struct Node * n1 = l1->item; struct Node * n2 = l1->item; while(n1->next) { if(n1->next->next) { n2 = n1->next; n1 = n1->next->next; }else{ n1 = n1->next; } } return n2; }
测试用例:1,2,3
结果: