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

链表系列之单链表常见面试题

2014-07-24 15:45 232 查看
创建单链表

typedef struct node
{
int data;
node *next;
}Node, *LinkList;
//建立链表
Node* createList1(const int a[], int n)
{
Node *head, *endPtr;
head = endPtr = NULL;

for(int i=0;i<n;i++)
{
Node *temp = new Node;
temp->data = a[i];
temp->next = NULL;

if(i==0)
{
head = endPtr = temp;
//			endPtr->next = NULL;
}
else
{
endPtr->next = temp;
endPtr = temp;
}
}

return head;
}
/*建立链表2*/
Node* createList2(int a[],int n)
{
Node *ListHead = new Node;
ListHead->data = a[0];
ListHead->next = NULL;

for(int i=n-1;i>0;i--)
{
Node *tmp = new Node;
tmp->data = a[i];
tmp->next = ListHead->next;
ListHead->next = tmp;
}

return ListHead;
}


1、从一个单链表中返回倒数第n个元素

维护两个指针,保持两个指针距离为n,当后面的指针为NULL时,前面的指针即为所求

实现:

Node *findNthToLast(Node *head, int n)
{
Node *ptr1 = head, *ptr2 = head;

if(head==NULL)   //如果链表为空
return NULL;
//保证ptr2与ptr1间隔n-1
if(n<=0)
return NULL;
else
{
for(int i=1;i<=n-1;i++)
{
ptr2 = ptr2->next;
if(ptr2==NULL)   //如果链表长度小于n
return NULL;
}
}

while(ptr2->next!=NULL)
{
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}

return ptr1;
}


2、给出单链表的头指针和一个结点指针,在O(1)时间删除该结点。

把下一个节点的data复制到需要删除的节点覆盖原来的内容,再把下一个节点删除,最后将该节点的next指针指向下下个节点。有两个特殊情况需要单独处理:要删除节点位于链表的尾部;链表只有一个节点。

实现

bool deleteNode(Node *head,Node *node)
{
if(head==NULL)
return false;

//要删除节点不是尾节点
if(node->next!=NULL)
{
Node *tmpPtr = node->next;
node->data = tmpPtr->data;
node->next = tmpPtr->next;

delete tmpPtr;
}
else
{
if(head==node)   //链表只有一个节点
{
delete node;
head = NULL;
}
else   //删除节点为尾节点
{
Node *tmp = head;
while(tmp->next!=node)
{
tmp = tmp->next;
}

tmp->next = NULL;
delete node;
}
}

return true;
}

3、单链表逆置

3.1递归实现:

void reverse(Node *pCur,LinkList &ListHead)
{
if(NULL==pCur||NULL==pCur->next)
{
ListHead = pCur;
}
else
{
Node *pNext = pCur->next;   //保存后继节点的指针
reverse(pNext,ListHead);
pNext->next = pCur;
pCur->next = NULL;
}
}


3.2非递归实现

void reverseList(LinkList &head)
{
if(head==NULL||head->next==NULL)   //边界检查
return NULL;

Node *pPre = head;   //用来指向前驱节点
Node *pCur = pPre->next;   //用来指向当前节点
Node *pNext = NULL;   //用来指向后继节点
while(pCur!=NULL)
{
pNext = pCur->next;   //保存后继节点的指针
pCur->next = pPre;   //将当前节点的指针域指向前驱节点
pPre = pCur;
pCur = pNext;
}

head->next = NULL;
head = pPre;   //新的头节点
}


4、从尾到头打印链表,要求不改变链表结构

4.1、借助栈来实现

void PrintListReversing(LinkList pHead)
{
stack<Node*> nodes;
Node* pNode = pHead;

if(pNode==NULL)
return;

while(pNode!=NULL)   //将节点依次入栈
{
nodes.push(pNode);
pNode = pNode->next;
}

while(!nodes.empty())   //出栈
{
pNode = nodes.top();
cout<<pNode->data<<endl;
nodes.pop();
}
}


4.2由于递归本质就是栈结构,因此也可以用递归实现

void PrintListReversing2(Node* pHead)
{
if(pHead==NULL)
return;

if(pHead!=NULL)
{
if(pHead->next!=NULL)
{
PrintListReversing2(pHead->next);
}
cout<<pHead->data<<endl;
}
}

5、使用单链表实现大数的加法

/*有两个由单链表表示的数。每个结点代表其中的一位数字。
数字的存储是逆序的, 也就是说个位位于链表的表头。
写一函数使这两个数相加并返回结果,结果也由链表表示。*/
//eg. Input:(3->9->6), (4->7->8->3)
//    Output:(7->6->5->4)
Node *ListAdd(Node* L1, Node* L2)
{
if(L1==NULL)
return L2;
if(L2==NULL)
return L1;

Node *ptr1 = L1, *ptr2 = L2, *ResultPtr=NULL, *TmpPtr=NULL;
int carry = 0;

Node *p_node = new Node();
p_node->data = (L1->data+L2->data)%10;
p_node->next = NULL;
carry = (L1->data+L2->data)/10;
ResultPtr = TmpPtr = p_node;
TmpPtr->next = NULL;
L1 = L1->next;
L2 = L2->next;

while(L1 && L2)
{
Node *pNode = new Node();
TmpPtr->next = pNode;

int tmp = L1->data+L2->data+carry;
carry = tmp/10;
pNode->data = tmp%10;
pNode->next = NULL;

TmpPtr = TmpPtr->next;
L1 = L1->next;
L2 = L2->next;
}

while(L1)
{
Node *pNode = new Node();
TmpPtr->next = pNode;

int tmp = L1->data+carry;
carry = tmp/10;
pNode->data = tmp%10;
pNode->next = NULL;

TmpPtr = TmpPtr->next;
L1 = L1->next;
}
while(L2)
{
Node *pNode = new Node();
TmpPtr->next = pNode;

int tmp = L2->data+carry;
carry = tmp/10;
pNode->data = tmp%10;
pNode->next = NULL;

TmpPtr = TmpPtr->next;
L2 = L2->next;
}

if(carry)
{
Node *pNode = new Node();
TmpPtr->next = pNode;

pNode->data = carry;
pNode->next = NULL;
}

return ResultPtr;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: