单链表常见笔试面试题总结

1.单链表逆置

#include <iostream>
using namespace std;

typedef int KeyType;
typedef struct Node
{
    KeyType value;
    Node *next;
}Node, *List;

void Reserver(List plist)
{
    // 链表为NULL/只有一个头节点/链表只有一个头节点和数据节点 --->不用交换
    if(plist==NULL|| plist->next==NULL|| plist->next->next==NULL)
    {
        return;
    }

    //链表至少有两个节点
    Node *p = plist->next;
    Node *q = p->next;
    Node *s;

    plist->next = NULL;//头节点要指向尾节点,先将其指针域赋为NULL
    while(q != NULL)
    {
        s = q->next;
        q->next = p;
        p = q;
        q = s;
    }
    plist->next = p;
    return;
}

2.逆序打印单链表

//1.如果要破坏单链表的结构,则像1题一样,使用断链-接链,然后遍历单链表
//2.如果不能破坏单链表的结构,可以使用stack,遍历后压栈,最后统一出栈
#include <iostream>
#include <stack>
using namespace std;

void PrintReserve(List plist)
{
    if(plist == NULL)
        return;

    stack<KeyType> st;

    Node *p = plist->next;
    while(p != NULL)
    {
        st.push(p->value);
        p = p->next;
    }

    while(!st.empty())
    {
        cout<<st.top()<<endl;
        st.pop();
    }
    return;
}

3.给定单链表,检测是否有环

思想:使用快慢指针,快指针每次走两格,慢指针每次走一格。如果有环,快慢指针总会相遇。如果快慢指针相遇,说明有环。如果快指针为NULL,则说明无环。

bool IsExitLoop(List plist)
{
    if(plist==NULL || plist->next==NULL)
    {
        return false;
    }

    Node *fast = plist;
    Node *slow = plist;

    while(fast!=NULL || slow!=NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            break;
        }
    }
    //退出循环,slow==false,有环  或者fast==NULL,没有环
    return fast==NULL ? false : true;
}

4.求环的长度
思想:从相遇节点开始,下次再走到该相遇点时经过的节点数为环的长度。

int LoopLength(List plist)
{
    if(plist==NULL || plist->next==NULL)
        return 0;

    Node *fast = plist;
    Node *slow = plist;
    while(fast!=NULL || slow!=NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            break;
        }
    }

    if(fast == NULL)//没有环
    {
        return 0;
    }

    Node *tmp = slow;
    slow = slow->next;
    int count = 1;
    while(slow != tmp)
    {
        slow = slow->next;
        ++count;
    }
    count += 1;
    return count;
}

5.给定单链表(head),如果有环的话返回从头结点进入环的第一个节点
思想:有定理证明,碰撞点到尾节点的距离=头节点到入口点的距离。慢指针从头节点开始走,快从相遇点开始走。当快指针为NULL时,慢指针所指的节点为环的第一个节点。

Node *FindEntryNode(List plist)
{
    if(plist==NULL || plist->next==NULL)
        return NULL;

    Node *fast = plist;
    Node *slow = plist;
    while(fast!=NULL || slow!=NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            break;
        }
    }

    if(fast ==NULL)
    {
        return NULL;
    }

    slow = plist;

    while(fast != slow)
    {
        fast = fast->next;
        slow = slow->next;
    }

    return slow==fast ? slow  : NULL;
}

6.给定两个单链表(plist1, plist2),检测两个链表是否有交点,如果有返回第一个交点

思想:如果plist1==plist2,链表相交点就是plist1。否则,先求出链表的长度,让快指针先走len1-len2步,然后快慢指针开始走,每次走一步。当快指针走到尾节点时,慢指针指向的节点为链表的相交点。

Node *FindNode(List plist1, List plist2)
{
    if(plist1==NULL || plist2==NULL)//指针不为NULL
    {
        return NULL;
    }

    if(plist1 == plist2)//指针指向同一个链表
    {
        return plist1;
    }

    Node *p = plist1;
    Node *q = plist2;

    int len1 = 0;
    int len2 = 0;

    for(; p!=NULL; p=p->next)
        ++len1;

    for(; q!=NULL; q=q->next)
        ++len2;

    int num = len1>len2 ? len1-len2 : len2-len1;

    int i =0;
    p = plist1;
    while(i<num && p->next!=NULL)
    {
        p = p->next;
        ++i;
    }
    q = plist2->next;

    while(p != q)
    {
        p = p->next;
        q = q->next;
    }

    return q;
}

7.只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点

思想:用后值覆盖前值,删除最后一个节点。切记:将倒数第二个节点的next域置为NULL。

bool DeleteNode(Node *p)
{
    if(p == NULL)
        return false;

    Node *tmp;
    while(p->next != NULL)
    {
        p->value = p->next->value;
        if(p->next->next == NULL)
        {
            tmp = p;
        }
        p = p->next;
    }

    tmp->next = NULL;
    delete p;

    return true;
}

8.给定单链表头结点,删除链表中倒数第k个结点

思想:快指针先走K步,然后快慢指针一块走,每次走1步,当快指针到达结尾的下一个节点(NULL)时,慢指针到达倒数第K个节点

bool DeleteKNode(List plist, int num)
{
    if(plist==NULL || plist->next==NULL || num<1)
        return false;

    Node *front = plist;
    for(int i=0; i<num; ++i)
    {
        if(front ==NULL)
            return false;
        front = front->next;
    }

    Node *back = plist;
    Node *tmp = plist;
    while(front != NULL)
    {
        front = front->next;
        back = back->next;
    }

    //back所指向的节点为倒数第K个节点
    DeleteNode(back);
    return true;
}

9.只给定单链表中某个结点p(非空结点),在p前面插入一个结点val

思想:在p后面添加一个节点s,s->value=p->value; p->value=val

bool InsertNode(Node *p, KeyType val)
{
    Node *s = (Node *)malloc(sizeof(Node));
    s->next = p->next;
    p->next = s;

    s->value = p->value; 
    p->value = val;
    return true;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值