链表的面试题(一)

来源:互联网 发布:js正则表达式 冒号 编辑:程序博客网 时间:2024/06/17 13:05

题目:

// 逆向打印单链表
void PrintListFromTail2Head(PNode pHead);
// 逆向销毁单链表
void DestroyListFromTail2Head(PNode* pHead);
// 删除单链表的非尾结点
void DeleteNotTailNode(PNode pos);
// 非头结点前插入data
void InsertNotHead(PNode pos, DataType data);
// 单链表实现约瑟夫环
PNode JosephCircle(PNode pHead, size_t M);
// 单链表的逆置–前后指针
PNode ReverseList(PNode pHead);
// 单链表的逆置–头插法
PNode ReverseList(PNode pHead);
// 查找链表的中间结点—要求不能遍历单链表
PNode FindMidNode(PNode pHead);

源程序:

void PrintListFromTail2Head(PNode pHead)//逆向打印{    if (pHead)    {        PrintListFromTail2Head(pHead->next);//运用递归的思想,找出最后一个节点,打印        printf("%d->", pHead->data);    }}
void DestroyListFromTail2Head(PNode* pHead)//逆向销毁{    if (*pHead)    {        DestroyListFromTail2Head(&((*pHead)->next));        free(*pHead);        *pHead = NULL;    }}

图解:
这里写图片描述

void DeleteNotTailNode(PNode pos){    if (pos == NULL || pos->next == NULL)        return;    else      //让pos保存pos下个节点的值,然后删除pos的下个节点      {        PNode pTemp = pos->next;        pos->data = pTemp->data;        pos->next = pTemp->next;        free(pTemp);    }}

图解:这里写图片描述

void InsertNotHeadNode(PNode pos, DataType data){    PNode PNewnode = NULL;    assert(pos);    PNewnode = ByeNode(data);    PNewnode->next = pos->next;    pos->next = PNewnode;    PNewnode->data=pos->data;    pos->data = data;}

约瑟夫环是一个自杀环,是约瑟夫和他的朋友为了活下来而想出的一种办法: 包括他和他的朋友在内的41个犹太人,为了不成为敌方的俘虏而相约自杀,自杀的顺序是这样产生的,他们41个人围成一个圈,从其中任意位置开始报数,每次报到3的人自杀,然后从下一个人又开始从1报数。直到最后就会剩下1个人,约瑟夫和他的朋友就站在了最后剩下的两个位置,从而生存下来。
我们可以使用单链表来实现,先将单链表构建成一个环,每次删除掉第M个元素,直到链表只剩下一个节点,那么就返回这个节点。
需要考虑:链表为空—-直接返回
链表不空时:
①报数
②删节点
还需要特别注意是头结点,因为在删除的过程中,你可能删除掉头结点,所以最好接收最后剩下的一个节点,因为此时phead保存的节点
已经可能被释放掉了,所以不能再使用phead,而是使用pCur,因为pCur始终指向的是链表中可以访问到的当前节点。
图形解析:这里写图片描述

PNode JosephCircle(PNode pHead, size_t M){    if (NULL == pHead)    {        return NULL;    }    PNode pCur = pHead;    PNode prev = pCur;    while (pCur != pCur->next)    {        size_t k = M;        while (--k)        {            pCur = pCur->next;        }        PNode pDel = pCur->next;        pCur->data = pDel->data;        pCur->next = pDel->next;        free(pDel);    }    return pCur;}

第一种方法–三个指针
首先考虑的还是链表为空和只有一个节点的情况—-直接返回。
还有链表中只有两个节点时,这种情况刚好在循环外可以处理。
在逆置的过程中肯定要进行循环,找到最后一个节点。
这里写图片描述
第二种方法–头插法:

简单说明:
就是每次将原链表的头节点摘下来(pHead->next = newnode),然后头插在新链表中(此时需要更新新链表的头结点),然后原来的头结点继续向后走,因为之前已经将头结点后的节点保存下来了;循环执行,直到原链表只剩下一个节点时,直接将最后这个节点头插在新链表即可。

PNode ReverseList(PNode pHead)//指针法{    if (NULL == pHead || NULL == pHead->next)    {        return pHead;    }    PNode prev = pHead;    PNode pCur = prev->next;    PNode pnext = pCur->next;    while (pnext)    {        pCur->next = prev;        prev = pCur;        pCur = pnext;        pnext = pnext->next;    }    pCur->next = prev;    pHead->next = NULL;    return pCur;}PNode ReverseList1(PNode pHead)//头插法{    if (NULL == pHead || NULL == pHead->next)    {        return pHead;    }    PNode pCur = pHead->next;    PNode newNode = NULL;    while (pCur)    {        pHead->next = newNode;        newNode = pHead;        pHead = pCur;        pCur = pCur->next;    }    pHead->next = newNode;    newNode = pHead;    return newNode;}

首先考虑:链表为空——返回NULL;
分为两种情况:
链表中有奇数个节点时,分析如图示:

这里写图片描述
链表中有偶数个节点时:
<code>这里写图片描述</code>

PNode FindMidNode(PNode pHead){    if (NULL == pHead || NULL == pHead->next)    {        return pHead;    }    PNode pSlow = pHead;    PNode pFast = pHead;    while (pFast && pFast->next)    {        pSlow = pSlow->next;        pFast = pFast->next->next;    }    return pSlow;}
原创粉丝点击