面试题:单链表的几种处理

首先链表节点的定义如下:

typedef struct node
{
    int data;
    struct node *next;
}Node;

面试题1:创建一个单链表

功能函数:

/****创建带有头结点的单链表******/
Node *creat(int n)
{
    Node *head,*p,*q;
    int x;
    head=(Node *)malloc(sizeof(Node)); /*创建头结点*/

    q=head;

    if(n>0)
    {
        printf("Please input the data of the node:");
        while(n>0)
        {
            scanf("%d",&x);
            p=(Node *)malloc(sizeof(Node));
            p->data=x;
            q->next=p;
            q=p;
            n--;
        }
    }
    q->next=NULL;
    return head;
}

面试题2:编程实现单链表的打印

功能函数:

/****打印单链表******/
void print(Node *head)
{
    Node *p;
    if(head->next==NULL)
    {
        printf("The LinkList is Empty !
");
        return;
    }
    p=head->next;
    while(p!=NULL)
    {
        printf("%d ",p->data);
        p=p->next;
    }
}

面试题3:编程实现从尾到头打印单链表(剑指offer)

思路1:第一反应是将链表中的指针反转,改变链表的方向,然后再从头打印出来(该方法改变了原来链表的结构,这就要看面试或笔试时的要求,可否改变链表结构)

思路2:遍历链表时是从头到尾,而打印链表时却是从尾到头,典型的“先进后出”——栈的特点,从而可以用栈来实现。没遍历一个节点,把该节点放到一个栈中,当遍历完整个链表后,再从栈顶开始逐个输出节点的值,此时输出的节点顺序已经反转过来了。

思路3:栈可以实现,而递归本质上也是一个栈结构,从而可以用递归来实现。即:没遍历到一个节点时,先递归输出其后面的一个节点的值,再输出该节点本身的值。

功能函数(思路3):

void Rev_print(Node *head)  
{ 
    Node *p;
    if(head==NULL || head->next==NULL)
        return;
    else
    {
        p=head->next;
        Rev_print(p);  
        printf("%d ",p->data);
    }
}  

 面试题4:编程实现查找单链表的中间节点

解题思路:A和B赛跑,其中A的速度是B的速度的两倍,当A到达终点时,B刚好到达中点

功能函数:

Node *find_midNode(Node *head)
{
    Node *p1,*p2;

    if(head==NULL || head->next==NULL) //链表为空,或是单结点链表直接返回头结点
        return head;

    p1=p2=head->next;

    while(1)
    {
        if(p2->next!=NULL && p2->next->next!=NULL)
        {
            p2=p2->next->next;
            p1=p1->next;
        }
        else
            break;
    }
    return p1;
}

面试题5:编程实现查找单链表的倒数第k个节点

思路1:首先求出单链表总的长度n,然后从链表的头节点开始遍历,当遍历到n-m个节点时,即为链表中倒数第m个节点

思路2:首先设置两个指针p1和p2,同时指向单链表的头节点,然后用p2遍历链表,将p2指向链表中第m个节点,接着将p1和p2同时进行遍历,当p2指向链表中末尾节点时,p1所指向的节点即为倒数第m个节点。

功能函数(思路1):

Node *Find_Rev_node_1(Node *head,int k)  //思路1
{
    Node *p;
    int n=0,i;
    p=head;
    while(p!=NULL)
    {
        n++;
        p=p->next;
    }

    if (n==0 || k>n)
    {
        return NULL;
    }
    
    p=head;
    for(i=0;i<n-k;i++)
    {
        p=p->next;
    }
    return p;
}

功能函数(思路2):

Node *Find_Rev_node_2(Node *head,int k)  //思路2
{
    Node *p,*p1,*p2;
    int n=0,i;

    p=head;
    while(p!=NULL)
    {
        n++;
        p=p->next;
    }

    if (n==0 || n<k)
    {
        return NULL;
    }
    p1=p2=head;
    for(i=0;i<k;i++)
    {
        p2=p2->next;
    }
    while(p2)
    {
        p2=p2->next;
        p1=p1->next;
    }
    return p1;
}

面试题6:编程实现判断单链表是否存在环形链表问题

 思路:使用快慢指针,慢指针每次只前进一步,快指针每次前进两步,直到慢指针遇上快指针。分别设置两个指针p1,p2.每循环一次,p2前进两步,p1前进一步,直到p2与p1相等或p2碰到NULL时结束。如果两个指针相等,则说明存在回环。

功能函数:

int Isloop_LinkList(Node *head)
{
    Node *p1,*p2;
    if(head==NULL || head->next==NULL) //链表为空,或是单结点链表直接返回头结点
        return 0;
    p1 = p2 = head;
    while(p2->next!=NULL && p2->next->next!=NULL)
    {
        p1=p1->next;
        p2=p2->next->next;
        if(p1==p2)
            return 1;
    }
    return 0;
}

 面试题7:编程实现单链表的逆置

 思路:遍历一遍链表,利用一个辅助指针保存当前节点的下一个节点,然后将当前节点的指针反转,利用已经存储的指针往后继续遍历

功能函数: 

Node *reverse_LinkList(Node *head)
{
    Node *p,*q,*r;

    if(head==NULL || head->next==NULL)  //链表为空,或是单结点链表直接返回头结点
        return head;

    p=head->next; //第一个节点
    q=p->next;    //保存第二个节点
    p->next=NULL;   //原第一个节点为末节点

    while(q!=NULL)
    {
        r=q->next;
        q->next=p;
        p=q;
        q=r;
    }
    head->next=p; //新的第一个节点为原末节点
    return head;
}

 测试程序:

头文件:

#include<stdio.h>
#include<stdlib.h>

主函数:

int main()
{
    int len,k;
    int flag=0;
    Node *LinkList,*Rev_LinkList;
    Node *a,*b,*c;

    printf("Please input the length of the LinkList:");
    scanf("%d",&len);
    LinkList=creat(len);
    printf("创建的链表如下:
");
    print(LinkList);
    printf("
");

    printf("从尾到头打印链表如下:
");
    Rev_print(LinkList); 
    printf("
");

    a=find_midNode(LinkList);
    printf("The middle node of the LinkList is:");
    printf("%d
",a->data);
    printf("
");

    printf("思路1:请输入要查找的倒数第几个节点? ");
    scanf("%d",&k);
    b=Find_Rev_node_1(LinkList,k);
    printf("链表的倒数第%d个节点为:",k);
    printf("%d
",b->data);
    printf("
");

    printf("思路2:请输入要查找的倒数第几个节点? ");
    scanf("%d",&k);
    c=Find_Rev_node_2(LinkList,k);
    printf("链表的倒数第%d个节点为:",k);
    printf("%d
",c->data);
    printf("
");

    flag=Isloop_LinkList(LinkList);
    if(flag==1)
        printf("该链表存在回环!
");
    else
        printf("该链表不存在回环!
");

    printf("链表反转后新的链表如下:
");
    Rev_LinkList=reverse_LinkList(LinkList);
    print(Rev_LinkList);
    printf("
");
    system("pause");
    return 1;
}

测试结果:

原文地址:https://www.cnblogs.com/kkdd-2013/p/3353773.html