C语言数据结构之如何快速查找链表的中间节点

腾讯面试题:如何快速查找指定链表的中间节点?

解法1:遍历法。

    先遍历一遍统计链表长度,然后再遍历长度的1/2便即是中间节点。

    时间复杂度O(3n/2)


解法2:快慢指针。(推荐)

    设置两个指向链表头结点的指针,一个指针的遍历速度是另一个指针的2倍,当快的指针遍历完毕,慢指针即是中间节点。

    时间复杂度O(n/2)


解法二比解法一速度快了足足3倍,可见算法的威力。


解法二代码:

LinkList.h

#ifndef _LINK_LIST_H_
#define _LINK_LIST_H_

#include 

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 
#include 
#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;
            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 

/**
    * 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

结果:

C语言数据结构之如何快速查找链表的中间节点_第1张图片

你可能感兴趣的:(C/C++)