链表面试题 解法总结

    xiaoxiao2021-03-25  119

    从尾打印链表

    1 用递归的方法,如果当前节点不为空,继续调打印函数传过去的参数下一个节点。

    If(PNode)

    {

      Print_list(PNode->PNext);

      Printf(%d->,PNode->data);

    }

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

      用代替法,把当前节点的下一个节点的值赋值给当前节点,在delete掉当前节点的下一个节点。

    3在无头单链表的一个非头节点前插入一个节点。

     在当前节点后先把这个节点插入,再交换一个节点的值

    4 单链表实现约瑟夫环

    PNode Josephcirclr(PNode Phead, SIZE_t M)

    它的主要思想是报数当为第M个节点是删除它,继续报数,返回最后一个节点。

    {

       pNode Cur=Phead;

       PNode DelNode;

       Size_t count;

       While(Cur!=Cur->Pnext)

      {

         Count=M;

         While(--M)  // M-- M 次,--MM-1次,因为第一个节点也算故走M-1次。

         {

            pCur=PCur->PNext;

         }

         DelNode=PCur->PNext;

         PCur->PNext=DelNode->PNext;

         PCur->data=DelNode->data;

         Free(DelNode);

       }

       Return PCur;

    }

    5 单链表排序 (冒泡)

     传一个参数为(PHead)

     定义3个指针,PTail ,PCur,PNext.

    PTail为尾随指针它为NULL,

    当外部while(PHead!=PTail)控制冒泡次数,内部while(PNext!=PTail)控制排序次数,进去首先给PCur=Phead,PNext=Phead->PNext,然后进入内部while进行冒泡。

    内部while,在走完一次冒泡后。PCur值为最后一个节点的值把它赋给PTailPTail=PCur.

    最终尾随指针走向head.

    6找到中间节点

    定义俩个指针一个为fast一个为low.fast2步,low走一步。

    While(fast&&fast->Next) fast=fast->Next->Next; low=low->Next.  出了whilelow为中间节点

    7找到 倒数第K个节点

    定义俩个指针,fast先走第K步,low再走,当fast走到NULLlow为倒数第K个节点。

    While(K--) { if(k==0)return ; fast=fast->Next;}while(fast){low=low->Next,fast=fast->Next;} return low;

    K-- 对应fast , - -k对应fast->Pnext判断条件不同

     

    8 逆制 单链表

    方法1 .  3指针法

     Pre PCur pnext ,pre记录当前节点的前一个节点,当前节点Next指向pre,这样我们就完成了逆制,但是如果没有Next就会丢失链表,故这就是Next的意义了

     2 递归

    Node* rev (Node*PHead)

    {

    Node * PCur =PHead;

    Node * Ppre =PHead;

    static Node* ptemp =PHead;

    static Node * ret =NULL;

    if (NULL == PCur->_PNext)

    {

    ret = PCur;

    }

    if (PCur->_PNext)

    {

    Ppre = PCur;

    PCur = PCur->_PNext;

    rev(PCur);

    PCur->_PNext = Ppre;

    }

    if (ptemp == Ppre)

    {

    Ppre->_PNext = NULL;

    return ret;

    }                                   // 递归

    }

     

    3 头插法不创建新节点

    Node * _rev_2(Node*PHead)

    {

    assert(PHead);

    Node *pre =PHead;

    Node * PCur = pre->_PNext;

    Node* NewHead =NULL;

    while (PCur)

    {

    pre->_PNext = NewHead;  // ppre插入在新链表的头节点之前

    NewHead = pre;    // 头节点指向新的节点。

    pre->_PNext = PCur;

    PCur = PCur->_PNext;

    }

    pre->_PNext = NewHead;   // 出while时 , PCur 指向 NULL ,ppre 指向最后一个节点故需处理最后一个节点在循环外

    NewHead = pre;

    return NewHead;

    }

    9 链表是否有交点,有的话返回交点。

      如果有交点 那么最后一个节点肯定相同,因为相交意味着有一个相同的节点,那么这个节点之后的所有Next的节点都相同,故相交 最后一个节点都相同。

     那么做法第一步遍历链表的同时 定义size_1 size_2 来一边遍历链表,一边记住链表大小。

    那么遍历完 得到俩链表的大小和最后一个节点。

    第二步 看最后一个节点是否相同,如果相同的话那么一定相交。

    相交后。 定义一个变量来记录他们的差值 gap,  while(gap - -)来使长的链表一直向后走,

    直到俩链表长度相同,得到新的一个长链表的节点,从这个节点开始俩链表长度相同。那么

    我们开始从这个节点再次遍历 俩链表, 直到俩节点相同,找到交点。

    10 链表是否带环,10(2)带环 环的长度,103)求入口点

     10(1) 定义一个快指针 一次走2步 慢 指针一次走1步 ,那么如有环快指针必定入环,等慢指针走进环,快指针必定在慢指针走完环一圈内追上慢指针。故可判断有环。

    注意while(fast && fast->Next) 因为fast=fast->next->next, 故得保住fastfast->next不为空。

    10(2) 环的长度很简单,由第一小问 返回的 是相遇的节点,定义个临时变量PNode= meetNode;那么while(PNode->Next!=meetNode)PNode走一圈遍历边即可,应注意count应初始化为1, 如果初始化为0,相遇点没有算到里面

    103) 第一种方法 定义俩个指针 一个为PH一个为PMPM从相遇点走 ,PH从头节点走,俩个每次都走一步当俩相遇的时候为入口点.因为设环长度为r ,入口点到 头节点为L,入口点到相遇点为X .  由快慢指针相遇得到存在2(L+X)=n*r+(L+x)式子存在,得到L=n*r-x,L=(n-1)r+r-x 。那么举个列子当n=1时(n至少等于1,因为快指针至少在走一圈后追上慢指针),L=r-x.它表示从相遇点走r-x就定于LL刚好为入口点到头节点距离,那么当一个从头开始走一个从相遇点开始走,当它们相遇时,PH=PM那个节点就是入口点。所以该公式L=(n-1)r+(r-x)代表,L这段距离等于n-1圈的长度加上r-x的长度,所以从PM开始每次走一步,从PH的开始每次走一步,只要相遇了,PM肯定是走了n-1圈加上r-x,而从相遇点走r-x后的该点必定是相遇点。

    即具体代码就是,PM=meetNode,PH=Phead,while(PH!=PM)PM=PM->Next,PH=PH->Next

    11  链表是否相交(可能带环),相交求交点 

    俩个链表都不带环 俩个链表都带环 俩个链表一个带一个不带 对于这种情况直接return NULL因为只要相交必定俩个都带或者俩个都不带

      思路:

      1先定义俩个fast和俩个low,遍历边。

      2遍历完后可根据if ((fast == NULL || fast->_PNext == NULL) && (fast2 == NULL || fast2->_PNext == NULL))判断出俩个都不带环

    对于不带环的,就定义俩个变量为PH,PH2,代表链表长度,分别变量链表到末尾,如何俩个末尾节点不相等那么俩链表肯定不相交returnNULL,如何相等的话,求gap

    为俩长度的差,然后长的链表一直while(gap!=0) p=p->next,gap--; 这样向后走到俩链表长短都一样了,再同时遍历俩链表直到节点相同那么它就是入口点

    3 if ((fast != NULL&&fast->_PNext!=NULL)&&(fast2 != NULL&&fast2->_PNext!=NULL))代表俩个都带环,那么先找到环的入口点Enter,Enter2,并记录头节点到入口点的

    距离为PH1,PH2。先看入口点是否相等,相等代表有交点,不相等返回NULL。如果那距离一个等于0,就把该链表头结点返回去,代表该链表自成一环,那么又相交,交点肯定为该自成一环的头结点。否则俩个PH都大于0,那么计算出gap,长的走到gap为0时,俩链表相等了长度,再遍历相同节点,找到后返回即可。

    4 进不去 2,3的代表一个有环,一个没环就返回NULL.

                                                         第3条分支,俩个都带环相交时的几种情景

    12  复杂链表的复制,有random的链表如何复制。 即 该节点有3个字段,一个为值一个为Next指针,一个为random指针。

    1 给每个节点后面都new一个 当前节点的副本,边复制边把他们连接起来。

    2 给随机域赋值,则新节点的random就等于老节点随即域的random->Next.

    3 把俩个链表拆分。

    转载请注明原文地址: https://ju.6miu.com/read-6055.html

    最新回复(0)