c语言实现单链表面试题(基础篇)

1.顺序便与单链表比较
顺序表:顺序表存储是将数据元素放到一块连续的内存储空间,相邻数据元素的存放地址也相邻,有动态存储和静态存储两种存储方式。
优点:(1)可以直接通过下标访问,支持随机访问,查找等效率较高。
(2)数据连续存放,空间利用率高,命中率高。
缺点:(1)当元素个数远小于预先分配的空间大小时,空间浪费比较严重;静态存储时,空间一经创建,大小不能改变,当需要存取的元素个数可能多于顺序表的元素个数时,会出现溢出问题。
(2)插入或删除数据效率较低,顺序表需要遍历移动元素。
链表:链表存储是程序运行过程中动态分配空间,相邻数据元素可任意存放,但所占存储空间分为两部分,一部分存放节点值,另一部分存放便是节点间关系的指针。
优点:(1)插入和删除效率较高,只需要改变指针指向即可。
(2)没有空间限制,只要存储器还有空间,就不会产生溢出问题。
缺点:(1)数据存放不连续,malloc开辟,空间碎片较多。
(2)查找速度较慢,当需要访问某个数据时,需要从第一个节点开始逐个查找。 适用场合:若线性表长度变化不大,且主要操作是查找很少插入删除时,可以采用顺序表;若线性表长度变化较大或者根本不知道多大,且其主要操作是插入删除很少查找时,可以采用链表,这样可以不用考虑存储空间大小问题。

//list.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#pragma once
typedef int DataType;
typedef struct ListNode
{
    DataType data;
    struct ListNode* next;
}ListNode;

2.从尾到头打印单链表

void PrintTailToHead(ListNode* ppHead)
{
    if (ppHead == NULL)
    {
        return;
    }
    PrintTailToHead(ppHead->next);
    printf("%d ", ppHead->data);
}

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

void ErasenoTail(ListNode* pos)
{
    ListNode* next;
    assert(pos&&pos->next);
    if (pos == -1)
    {
        return;
    }
    next = pos->next;
    pos->data = next->data;
    pos->next = next->next;
    free(next);
}

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

void InsertnoTail(ListNode* pos,DataType x)
{
     assert(pos);
     if (pos == -1)
     {
         return;
     }
     ListNode* next= BuyNode(pos->data);
     next->next = pos->next;
     pos->next = next;
     pos->data = x;
}

5.单链表实现约瑟夫环

ListNode* Joseph(ListNode* hus, size_t k)
{
    ListNode* man,*next;
    assert(hus);
    man = hus;
    while (man->next != man)
    {
        size_t count = k;
        while (--count)
        {
            man = man->next;
        }
        next = man->next;
        man->data = next->data;
        man->next = next->next;
        free(next);
    }
    return man;
}

6.逆置/反转单链表

void Reverse(ListNode** ppHead)
{

    if (*ppHead == NULL)
    {
        return ;
    }
    else
    {
        ListNode* n0 = NULL, *n1 = *ppHead, *n2 = n1->next;
        while (n1)
        {
            n1->next = n0;
            n0 = n1;
            n1 = n2;
            if (n2)
            {
                n2 = n2->next;
            }
        }
        *ppHead = n0;
    }
}

7.单链表排序(冒泡排序&快速排序)

void SortList(ListNode* pHead)
{
    ListNode* tail = NULL;
    if (pHead==NULL&&pHead->next==NULL)
    {
        return;
    }
    while (tail!=pHead)
    {
        int exchange = 0;
        ListNode* cur = pHead, *next = cur->next;
        while (next != tail)
        {
            if (cur->data > next->data)
            {
                exchange = 1;
                DataType tmp = cur->data;
                cur->data = next->data;
                next->data = tmp;
            }
            cur = cur->next;
            next = next->next;
        }
        if (exchange == 0)
        {
            break;
        }
        tail = cur;
    }
}

8.合并两个有序链表,合并后依然有序

ListNode* MergeList(ListNode* list1, ListNode* list2)
{
    ListNode* list,*tail;
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;
    if (list1->data < list2->data)
    {
        list = list1;
        list1 = list1->next;
    }
    else
    {
        list = list2;
        list2 = list->next;
    }
    tail = list;
    while (list1&&list2)
    {
        if (list1->data < list2->data)
        {
            tail->next = list1;
            list1 = list1->next;
        }
        else
        {
            tail->next = list2;
            list2 = list2->next;
        }
        tail = tail->next;
    }
    if (list1 != NULL)
    {
        tail->next = list1;
    }
    else
    {
        tail->next = list2;
    }
    return list;
}

9.查找单链表的中间节点,要求只能遍历一次链表

ListNode* FindMidNode(ListNode* pHead)
{
    ListNode* slow = pHead;
    ListNode* fast = pHead;
    while (fast && fast->next&&fast->next->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

10.查找单链表的倒数第k个节点,要求只能遍历一次链表

ListNode* FindTailkNode(ListNode* pHead, size_t k)
{
    ListNode* slow = pHead, *fast = pHead;
    while (--k)
    {
        if (fast == NULL)
        {
            return NULL;
        }
        fast = fast->next;
    }
    while (fast->next)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

//test.c

//Reverse/ErasenoTail/InsertnoTail/PrintTailToHead
void TestList1()
{
    ListNode* list = NULL;
    PushBack(&list, 0);
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    PrintList(list);
    PrintTailToHead(list);
    Reverse(&list);
    PrintList(list);
    ErasenoTail(Find(list,2));
    PrintList(list);
    InsertnoTail(Find(list, 3),30);
    InsertnoTail(Find(list, 2),40);
    PrintList(list);
}
//Joseph
void TestList2()
{
    ListNode* tail;
    ListNode* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    tail = Find(list, 5);
    tail->next = list;
    printf("live:%d\n", Joseph(list, 3)->data);
}
//SortList
void TestList3()
{
    ListNode* list = NULL;
    PushBack(&list, 5);
    PushBack(&list, 3);
    PushBack(&list, 2);
    PushBack(&list, 7);
    PushBack(&list, 9);
    SortList(list);
    PrintList(list);
}
//MergeList
void TestList4()
{
    ListNode* list;
    ListNode* list1 = NULL;
    ListNode* list2= NULL;
    PushBack(&list1, 1);
    PushBack(&list1, 3);
    PushBack(&list1, 5);
    PushBack(&list1, 7);
    PushBack(&list1, 9);
    PushBack(&list2, 0);
    PushBack(&list2, 2);
    PushBack(&list2, 4);
    PushBack(&list2, 6);
    PushBack(&list2, 8);
    list=MergeList(list1, list2);
    PrintList(list);
}
//FindMidNode/FindTailkNode
void TestList5()
{
    ListNode* list1=NULL;
    PushBack(&list1, 0);
    PushBack(&list1, 1);
    PushBack(&list1, 3);
    PushBack(&list1, 5);
    PushBack(&list1, 7);
    PushBack(&list1, 9);
    SortList(list1);
    printf("mid:%d\n", FindMidNode(list1)->data);
    printf("tail k:%d\n", FindTailkNode(list1,3)->data);
}
#include test.h
int main()
{
    TestList5();
    system("pause");
    return 0;
}

“`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值