C语言实现单链表面试题——基础篇(上)

1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?

  1. 顺序表的特点是逻辑上相邻的数据元素,物理存储位置也相邻,并且,顺序表的存储空间需要预分配。
    它的优点 :
    (1)方法简单,各种高级语言中都有数组,容易实现
    (2)不用为表示节点间的逻辑关系而增加额外的存储开销。
    (3) 顺序表具有按元素序号随机访问的特点
    它的缺点:
    (1)插入时需要将后面的元素逐个挪动比较麻烦
    (2)动态存储比较麻烦,开大了浪费,开小了不够用
  2. 在链表中逻辑上相邻的数据元素,物理存储位置不一定相邻,它使用指针实现元素之间的逻辑关系。并且,链表的存储空间是动态分配的。
    它的优点:插入删除方便
    它的缺点:
    (1) 需要占用额外的空间,来存储下一个节点的地址
    (2)不能随机存取元素
    应用场景:
    在一次可开辟足够空间且节省空间则用顺序表
    在需要多次增删查改则选用链表。

2.从尾到头打印链表:

思考方法:首先我们需要找到最后一个节点,且还能回到上一个节点,我们可以想到递归,我们传头结点”pList”给函数,函数判断节点是否为NULL,若为NULL,则打印NULL,反之我们继续调用函数,传pList->next,则实现了:先找到最后一个节点,并在函数返回后找到上个节点的值pList->data;

void PrintHeadtoTail(ListNode *pList)//从尾到头打印链表
 {
     if(pList == NULL)
     {
         printf("NULL");
         return;
     }
     PrintHeadtoTail(pList->next);//传pList->next
    //函数返回时不会改变plist的值
    printf("<-%d",pList->data);  //打印pList->data
 }

3.删除一个无头链表的非尾节点

函数名: void ErasenonTail(ListNode *pos);

1.当看到这个问题的时候,我想这么简单的问题,我想到的代码是:

void ErasenonTail(ListNode *pos)
{
    ListNode *pavi = pos;
    pos = pos->next;
    free(pavi);
}

2.但运行之后,我发现程序崩溃了,我就很纳闷。我就一步一步的调试发了许多很可笑的问题:

void ErasenonTail(ListNode *pos)
 //这里的pos虽然值和链表节点的值相同,但修改pos链表不会改变
{
    ListNode *pavi = pos;
    pos = pos->next;//pos是值传递
    free(pavi);
    pavi = NULL;//这里就更可笑了,函数内部定义的值置空
}

3.经过这一次的教训,我发现不能小看任何一道题,所以我利用画图得到了一个办法
这里写图片描述
代码:

 void ErasenonTail(ListNode *pos)//
 {
     assert(pos);
     ListNode *tail = pos->next;
     pos->data = tail->data; //对指针的引用改变指针所指向空间的值
     pos->next = tail->next;
     free(tail);
 }

4. 在无头单链表的一个节点前插入一个节点

这个题和上一个题的方法一样,在链表节点后加一个节点简单,再交换这个节点和新添加的节点的数据;

 void InsertnonTail(ListNode* pos, DataType x)//无头链表节点前添加
 {
     assert(pos);
     ListNode *pavi = NULL;
     Compatibo(&pavi);
     pavi->data = pos->data;
     pos->data = x;
     pavi->next = pos->next;
     pos->next = pavi;
 }

5. 单链表实现约瑟夫环

这里写图片描述

//头结点 ppList ,开始的人数 n, 每次数的数m
void Josephus(ListNode **ppList,int n, int m)
{
    assert(ppList);
    ListNode *ret = NULL;
    ListNode *tail = NULL;
    int i = 0;
    for(i=1; i<=n; i++)
    {
        PushBack(ppList, i);
    }
    ret = Find(*ppList,n);
    ret->next = *ppList;//创建了一个循环链表
    while(*ppList != (*ppList)->next)
    {
        ret = *ppList;
        for(i=0;i<m-1; i++)//找出要删除的节点
        {
            ret = ret->next;
        }
        EraseCrc(ppList, ret);//删除节点(注意头结点不能变)
        //在删除头一个节点的时候,应利用无头节点删除的方法
    }
    printf("%d\n",(*ppList)->data);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章