您的位置:首页 > 职场人生

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

2017-07-18 17:57 651 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: