链表面试题(一)

1.从尾到头打印单链表

思路导图:
这里写图片描述


代码实现:

void LinkListPrint(LinkList*head)
{
    assert(head != NULL);
    LinkList*end = NULL;
    while (end != head)
    {
        LinkList*cur = head;
        while (cur->_next!=end)
        {
            cur = cur->_next;
        }
        printf("%d\n", cur->_data);
        end = cur;//每次范围会缩小一个
    }

}


2.删除一个无头单链表的非尾节点(不能遍历链表)

思路导图:
这里写图片描述


代码实现:

void Remove(LinkList*node)
{
    assert(node != NULL);
    LinkList*cur = node->_next;
    node->_data = cur->_data;
    node->_next = cur->_next;
    free(cur);

}


3.在无头单链表的一个非尾节点前插入一个节点(不能遍历单链表)

思路导图:
这里写图片描述


代码实现:

void Insert(LinkList*node, size_t x)
{
    assert(node != NULL);
    LinkList*cur = BuyNode(x);
    cur->_next = node->_next;
    node->_next = cur;
    swap(cur->_data, node->_data);
}


4.单链表实现约瑟夫环

思路分析:
这里写图片描述


代码实现:

LinkList*JosephCircle(LinkList*node, size_t k)
{
    if (node == NULL || node->_next == node)
        return node;
    LinkList*cur = node;
    while (cur != cur->_next)
    {
        int i = 0;
        while (i != k)
        {
            cur = cur->_next;
            i++;
        }
        //删除第k个节点
        LinkList*tmp = cur->_next;
        cur->_data = tmp->_data;
        cur->_next = tmp->_next;
        free(tmp);
    }

    return cur;

}


5.逆置单链表

——头插法

思维导图:
这里写图片描述


详细过程:
这里写图片描述

这里写图片描述


代码实现:

LinkList* Reserve(LinkList*node)
{
    if (node == NULL || node->_next == node)
        return node;
    LinkList*newNode = NULL;
    while (node != NULL)
    {
        LinkList*cur = node->_next;
        node->_next = newNode;
        newNode = node;
        node = cur;

    }
    return newNode;
}


——三指针法

思维导图:

这里写图片描述


代码实现:

LinkList*ReserveList(LinkList*node)
{
    LinkList*n1, *n2, *n3;
    if( node==NULL||node->_next=NULL)
    {
        return node;
    }
    n1 = node;
    n2 = n1->_next;
    n3 = n2->_next;

    n1->_next = NULL;//方便逆置过来时,原来的头结点应该指向空

    while (n2 != NULL)
    {
        n2->_next = n1;
        n1 = n2;
        n2 = n3;
        while (n3 != NULL)
        {
            n3 = n3->_next;
        }
    }
    return n1;//返回头结点
}


6.单链表排序——冒泡

思维导图:

这里写图片描述


代码实现:

void LinkListBubbleSort(LinkList*node)
{
    LinkList*tail = NULL;
    DataType flag = 0;
    if (node = NULL || node->_next == NULL)
    {
        return node;
    }
    while (node!=tail)//链表不能为空
    {
        LinkList*cur = node;
        LinkList*next = cur->_next;
        while (next != tail)
        {
            if (cur->_data > next->_data)
            {
                flag = 1;
                DataType tmp = cur->_data;
                cur->_data = next->_data;
                next->_data = tmp;
            }
            cur = cur->_next;
            next = next->_next;
        }

        if (flag == 0)
        {
            return;
        }
        tail = cur;//缩小范围
    }

}


7.合并两个有序单链表,使得合并后依然有序——以排升序为例

//非递归

LinkList* MergeLinkList(LinkList* pHead1, LinkList* pHead2)
{
    if (pHead1 == NULL)
    {
        return pHead2;
    }
    if (pHead2 == NULL)
    {
        return pHead1;
    }
    LinkList*newHead = NULL;//把排序好的链表存放在这个里面
    LinkList* tail = NULL;//记录当前链表的最后一个位置

    if (pHead1->_data < pHead2->_data)
    {
        newHead = pHead1;
        pHead1 = pHead1->_next;
    }
    else
    {
        newHead = pHead2;
        pHead2 = pHead2->_next;
    }

    tail = newHead;//确定新链表的头结点

    while (pHead1 != NULL&&pHead2 != NULL)
    {
        if (pHead1->_data < pHead2->_data)
        {
            tail->_next = pHead1;
            pHead1 = pHead1->_next;
        }
        else
        {
            tail->_next = pHead2;
            pHead2 = pHead2->_next;

        }
        tail = tail->_next;//插入一个节点,tail便向后挪一个
    }

    if (NULL == pHead1)
    {
        tail->_next = pHead2;
    }
    else if (NULL == pHead2)
    {
        tail->_next = pHead1;
    }

    return newHead;
}

// 递归

LinkList* MergeLinkList(LinkList* pHead1, LinkList* pHead2)
{
    if (pHead1 == NULL)
    {
        return pHead2;
    }
    if (pHead2 == NULL)
    {
        return pHead1;
    }

    LinkList*newHead = NULL;//把排序好的链表存放在这个里面

    while (pHead1 != NULL && pHead2 != NULL)
    {
        if (pHead1->_data < pHead2->_data)
        {
            newHead = pHead1;
            newHead->_next = MergeLinkList(pHead1->_next, pHead2);
        }

        else
        {
            newHead = pHead2;
            newHead->_next = MergeLinkList(pHead1, pHead2->_next);
        }

    }
}


8.查找一个链表的中间节点,要求只能遍历一次

思维导图:

这里写图片描述


代码实现:

LinkList* FindMidNode(LinkList* node) // 遍历一遍找到链表中间节点
{
    if (node != NULL&&node->_next != NULL)
    {
        return node;
    }
    LinkList*fast = node;
    LinkList*slow = node;
    while (fast->_next != NULL)
    {
        fast = fast->_next->_next;
        slow = slow->_next;
    }
    return slow;
}


9.查找单链表的倒数第k个节点,要求只能遍历一次链表

思路分析:

1.定义两个指针 fast 和slow
2.快指针一次走两步,慢指针一次走一步
3.fast指针先走k-1步,然后快慢指针同时走
3.当快指针走到尾时,慢指针所在的节点就是倒数第k个节点

代码实现:

LinkList* FindReciprocalKNode(LinkList* node, size_t k) //遍历一遍查找倒数第K个节点
{
    assert(node!= NULL&&k!=0);

    LinkList*fast = node;
    LinkList*slow = node;
    while (fast->_next != NULL)
    {
        k--;
        if (k <= 0)
        {
            slow = slow->_next;//当快指针走了k-1步后,即走到第k个节点时,慢指针再开始走
        }
        fast = fast->_next;

    }

    //当k=链表长度时,k--之后得到——k的最大值,是1
    if (k <= 1)  
    {
        return slow;
    }
    else  //当k的值大于1时,代表查找失败(此种情况是k的值>链表长度时)
    {
        return NULL;
    }
}


10.删除链表的倒数第k个节点(不能遍历链表)

思路分析:

1.首先用快慢指针法找到倒数第k个节点
2.然后调用删除节点的函数进行删除

代码实现:

void RemoveReciprocalKNode(LinkList*node, size_t k)
{
    assert(node != NULL&&k != 0);
    LinkList*fast = node;
    LinkList*slow = node;

    while (fast->_next != NULL)
    {
        --k;
        if (k <= 0)//快指针先走k步,慢指针才开始走。
        {
            slow = slow->_next;
        }

        fast = fast->_next;

        if (k <= 1)//当k=链表长度时,k有最大值,k=1
        {
            Remove(slow);//调用删除节点的函数
        }

    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值