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

面试常见编程题专题一:链表

2016-03-09 20:20 756 查看
最近在准备找实习,各种刷题。准备把刷过的题以专题的形式做个总结。

先说说链表,链表是一种动态的数据结构,其操作需要通过指针来完成,因此常被用作考察重点。

本文中的单向链表节点定义如下:

struct ListNode
{
int value;
ListNode *next;
ListNode(int x):value(x),next(NULL);
};
1、翻转链表:定义一个函数,输入一个链表的头结点,反转链表并输出头结点。
ListNode *reverselist(ListNode *p)
{
ListNode *pReversedHead = NULL;
ListNode *pNode = p;
ListNode *pPrev = NULL;
ListNode *pNext;
while (pNode != NULL)
{
pNext = pNode->next;
if (pNext == NULL)    pReversedHead =pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
2、从尾到头输出链表(通过递归或者栈来实现,递归的本质就是栈,递归在链表非常长的时候,有可能造成函数调用栈溢出)

void PrintListReversely(ListNode *head){
stack<ListNode *> node;
ListNode *p = head;
while (p!=NULL)
{
node.push(p);
p = p->next;
}
while (!node.empty())
{
p = node.top();
cout<<p->value<<endl;
node.top();
}

}

3、合并两个有序链表

ListNode *merge(ListNode *head1, ListNode *head2){
    if (head1 == NULL)
         return head2;
    else
    {
         if (head2 == NULL)
             return head1;
    }
    ListNode *p=NULL;
    for (; head1 != NULL&&head2 != NULL; p = p->next){
         if (head1->value > head2->value){
             p = head2;
             head2 = head2->next;
         }
         else{
             p = head1;
             head1 = head1->next;
         }
    }
    p->next = head1!= NULL ? head1:head2;
    /*递归法
    if (head1->value > head2->value){
         p = head2;
         p->next = merge(head1,head2->next);
    }
    else{
         p = head1;
         p->next = merge(head1->next,head2);
    }
    */
    return p;
}
4、找出链表倒数第K个数
ListNode *findKthend(ListNode *head, unsigned int k){
if (head == NULL || k == 0) return NULL;
ListNode *first=head;        
ListNode *second=head;
for (int i = 1; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}
while (first->next!=NULL)
{
first = first->next;
second = second->next;
}
return second;

}

5、删除链表倒数第K个数并返回头结点(思路:找出倒数k+1个节点并使其指向倒数k-1个节点)

 ListNode* removeNthFromEnd(ListNode* head, int k) {

            ListNode* dummy=new ListNode(-1);

            dummy->next=head;

            ListNode* record=dummy;

            for (int i = 0; i < k; i++){
if (first->next != NULL){
first = first->next;
}
else
{
return
NULL;
}
}

            ListNode* result=dummy;

            while(record->next){

                result=result->next;

                record=record->next;

            }

            result->next=result->next->next;

            return dummy->next;

        }

6、从无头单链表中删除节点

void deleterandnode(ListNode *p){
if (p== NULL)
return;
ListNode *pNext = p->next;
if (pNext != NULL){
p->value = pNext->value;
p->next = pNext->next;
delete pNext;
}

}

7、添加元素

void addtotail(ListNode **L, int value){
ListNode pNode=ListNode(value);
ListNode *p = &pNode;
if (*L == NULL){
*L = p;
}
else{
ListNode *pnode = *L;
while (pnode->next!=NULL){
pnode = pnode->next;
}
pnode->next = p;
}

}

8、判断是否有环最好的方法是时间复杂度O(n),空间复杂度O(1) 的。设置两个指针,一个快一个慢,快的指针每次走两步,慢的指针每次走一步,如果快指针和慢指针相遇,则说明有环。

bool hascycle(ListNode *head){

i
ListNode *slow = head, *fast = head;
while (fast&&fast->next) //考虑节点个数为奇数和偶数的情况
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) return true;
}
return false;

}

9、判断一个单链表的环入口,如果没有环,则返回NULL;(下面为我复制的 各位可以自己画个示意图理解下)

设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。

a + x = nr

a + x = (n – 1)r +r = (n-1)r + L - a

a = (n-1)r + (L – a – x)

(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:

ListNode *FindLoopPort(ListNode *head){
if (head == NULL || head->next == NULL){
return NULL;
}
ListNode *slow = head, *fast = head;
while (fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast) break;
}
if (fast != slow) return
NULL;
slow = head;
while (slow != fast){
slow = slow->next;
fast = fast->next;
}
return fast;

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