链表面试题——上

1.从尾到头打印单链表

思路:用两个指针来控制打印:
①tail先指向NULL,然后指针cur从头往后走,走到tail前一个位置,就是最后一个节点,打印这个节点。
②tail往前走,tail指向链表最后一个节点,再让cur走到tail前一个位置,打印。
………….

void SListPrintTailToHead(SListNode* pHead) //从尾到头打印单链表
{
    SListNode* tail = NULL;
    SListNode* cur = NULL;

    while (tail != pHead)
    {
        cur = pHead;
        while (cur->_next != tail)
        {
            cur = cur->_next;
        }
        printf("%d ", cur->_data);

        tail = cur;
    }
}

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

思路:找到我们可以找到pos的下一个节点,把pos下一个节点的值给pos,再删除pos->next。这样就相当于删除了pos。

void SListRemove(SListNode* pos)
{
    assert(pos != NULL && pos->_next != NULL);

    SListNode* next = pos->_next;
    pos->_data = next->_data;
    pos->_next = next->_next;
    next->_next = NULL;
    free(next);
}

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

思路:在pos后面插入一个节点newNode,它的数据域放的是pos->_data,然后把pos-> _data改成x,这样就相当于在pos前面插入一个值为x的节点

void SListInsert2(SListNode* pos, DataType x)//在无头单链表的一个节点前插入一个节点(不能遍历链表)
{
    assert(pos != NULL);

    SListNode* tail = pos->_next;
    SListNode* newNode = BuySListNode(pos->_data);

    newNode->_next = pos->_next;
    pos->_next = newNode;
    pos->_data = x;
}

4.单链表实现约瑟夫环(JosephCircle)

思路:先把链表连接成环,从1数到k,其实是往前移动k-1次,然后删除第k个链表。当链表只剩下最后一个节点时,循环结束。

SListNode* JosephCircle(SListNode* pHead, DataType k)
{
    SListNode* cur = pHead;
    SListNode* next;
    while (cur->_next != cur)
    {
        DataType count = k;
        while (--count) //k-1次循环
        {
            cur = cur->_next;
        }
        next = cur->_next;
        cur->_data = next->_data;
        cur->_next = next->_next;
        free(next);
    }
    return cur;
}

5.逆置/反转单链表

思路:定义三个结构体指针进行操作
注意:①开始之前把n1->_next = NULL 。②循环结束的条件

/* 方法一 */
SListNode* ReverseList(SListNode* list)//逆置/反转单链表
{
    SListNode* n1, *n2, *n3;
    if (list == NULL || list->_next == NULL)
    {
        return list;
    }
    n1 = list;
    n2 = n1->_next;
    n3 = n2->_next;

    n1->_next = NULL;
    while (n2 != NULL)
    {
        n2->_next = n1;
        n1 = n2;
        n2 = n3;

        if (n3 != NULL)
        {
            n3 = n3->_next;
        }
    }
    return n1;
}
/* 方法二 */
SListNode* ReverseList2(SListNode* list) 
{
    SListNode* newNode = NULL;
    SListNode* cur = list;

    while (cur != NULL)
    {
        SListNode* next = cur->_next;
        cur->_next = newNode;
        newNode = cur;
        cur = next;
    }
    return newNode;
}

6.单链表排序(冒泡排序&快速排序)

冒泡排序
void SListBubbleSort(SListNode* list) //冒泡排序
{
    SListNode* tail = NULL;

    while (tail != list)
    {
        int flag = 0;
        SListNode* cur = list;
        SListNode* next = list->_next;

        while (next != tail)
        {
            if (cur->_data > cur->_next->_data)
            {
                flag = 1;
                DataType tem = cur->_data;
                cur->_data = cur->_next->_data;
                cur->_next->_data = tem;
            }
            cur = cur->_next;
            next = next->_next;
        }
        if (0 == flag)
        {
            return;
        }
        tail = cur;
    }
}

7.合并两个有序链表,合并后依然有序

递归法:

SListNode* MergeSList(SListNode* pHead1, SListNode* pHead2)
{
    if (NULL == pHead1)
    {
        return pHead2;
    }
    else if (NULL == pHead2)
    {
        return pHead1;
    }

    SListNode* newMergeListHead = NULL; 

    if (pHead1->_data < pHead2->_data)
    {
        newMergeListHead = pHead1;
        newMergeListHead->_next = MergeSList(pHead1->_next, pHead2);
    }
    else
    {
        newMergeListHead = pHead2;
        newMergeListHead->_next = MergeSList(pHead1, pHead2->_next);
    }

    return newMergeListHead;
}
/*非递归*/
SListNode* MergeSList(SListNode* pHead1, SListNode* pHead2)
{
    if (NULL == pHead1)
    {
        return pHead2;
    }
    else if (NULL == pHead2)
    {
        return pHead1;
    }

    SListNode* newMergeListHead = NULL;//把排序好的链表存到这里面
    SListNode* tail = NULL;  //记录新链表最后一个节点


    if (pHead1->_data < pHead2->_data)
    {
        newMergeListHead = pHead1;
        pHead1 = pHead1->_next;
    }
    else
    {
        newMergeListHead = pHead2;
        pHead2 = pHead2->_next;
    }
    tail = newMergeListHead; //确定好第一个结点

    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;
    }

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

    return newMergeListHead;
}

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

思路:定义两个指针,一个快指针,一个慢指针。快指针一次走两步,慢指针一次走一步。当快指针走到尾节点时,慢指针刚好走到中间节点。

注意:所有快慢指针题必须主要循环结束的条件。

SListNode* FindMidNode(SListNode* list) // 遍历一遍找到链表中间节点
{
    assert(list != NULL);
    SListNode* pFast = list;
    SListNode* pSlow = list;

    while (pFast != NULL && pFast->_next!= NULL)
    {
        pFast = pFast->_next->_next;
        pSlow = pSlow->_next;
    }

    return pSlow;
}

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

思路:快慢指针法,首先pFast和pSlow都指向第一个节点,然后让pFast先往前走k-1步,最后pFast和pSlow同时走,当pFast走到最后一个节点时,pSlow走到倒数第k个节点

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

    SListNode* pFast = list;
    SListNode* pSlow = list;

    while (pFast->_next != NULL)
    {
        k--;
        if (k <= 0)  //当pFast走到正数第K个节点时,pSlow开始走
        {
            pSlow = pSlow->_next;
        }
        pFast = pFast->_next;
    }

    if (k <= 1)  //查找成功时,k的最大值是1(当k=链表长度时)
    {
        return pSlow;
    }
    else  //大于1代表查找失败
    {
        return NULL;
    }
}

10.删除链表的倒数第K个结点

void RemoveReciprocalNode(SListNode* list, int k) //遍历一遍删除倒数第K个节点
{
    assert(list != NULL && k != 0);

    SListNode* pFast = list;
    SListNode* pSlow = list;

    while (pFast->_next != NULL)
    {
        k--;

        pFast = pFast->_next;

        if (k <= 0)  //当pFast走到正数第K个节点时,pSlow开始走
        {
            pSlow = pSlow->_next;
        }
    }

    if (k <= 1)  //查找成功时,k的最大值是1(当k=链表长度时)
    {
        SListRemove(pSlow); //用函数:删除一个无头单链表的非尾节点
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值