单链表经典试题

逆序打印单链表
void LinkListReversePrint(LinkNode* head); 

思路:使用递归, 通过栈的后进先出特性, 实现单链表的逆序输出

不允许遍历链表, 在 pos 之前插入
void LinkListInsertBefore(LinkNode** head, LinkNode* pos, 
                          LinkType value); 

思路:先插到pos之后,再和pos交换值

单链表逆置
void LinkListReverse(LinkNode** head); 

思路:每次删除第一个结点的下一个结点,然后头插

单链表的冒泡排序
void LinkListBubbleSort(LinkNode* head); 

思路:和传统冒泡排序一样,可以只比较两个结点值的大小,然后交换值

将两个有序链表, 合并成一个有序链表
LinkNode* LinkListMerge(LinkNode* head1, LinkNode* head2); 

思路:两个链表从第一个开始比较,小的那个插入到一个新的头结点后面,如此循环,直到某一链表为空,将另一个链表剩余的部分插入到新链表后面

找到倒数第 K 个节点.
LinkNode* FindLastKNode(LinkNode* head, size_t K); 

思路:两个指针,slow和fast, fast先走k步, 然后slow和fast一起走,当fast走完时,slow的位置就是第k个结点

删除倒数第K个节点
void EraseLastKNode(LinkNode** head, size_t K); 

思路:先找到再删除

判定单链表是否带环. 如果带环返回1
LinkNode* HasCycle(LinkNode* head); 

思路:设置指针slow和fast,slow一次走一步,fast一次走两步,如果它们从头出发,再次相遇了,则说明链表带环.

如果链表带环, 求出环的长度
size_t GetCycleLen(LinkNode* head); 

思路:从它们相遇的地方标记一个指针,然后一次走一步,计数器加1,再次相遇,得出环长

如果链表带环, 求出环的入口
LinkNode* GetCycleEntry(LinkNode* head); 

思路:环内快慢指针相遇的位置到入口的距离再加上N倍的环长 = 头结点到环入口的距离
这里写图片描述
即上图 XY= ZY+ N*环长 N>=0

判定两个链表是否相交. 链表可能带环
int HasCrossWithCycle(LinkNode* head1, LinkNode* head2); 

有三种情况
1, 链表1带环, 链表2 不带环, 则两个链表肯定不相交, 因为一旦相交, 两个链表必定都带环.
2, 两个都带环, 交点在环外
如果两个都带环,那么求它们的环入口点,若两入口点相同,则两个链表环外相交
3, 两个都带环, 交点在环上
求环入口点,然后从入口点走,能遇到另一个入口点,则环上相交

求两个有序链表的交集
LinkNode* UnionSet(LinkNode* head1, LinkNode* head2); 

定义两个指针 cur1 和 cur2 分别指向两个链表, 再创建一个新链表, 然后从第一个开始比较, 若他们的值相等, 创建一个新结点, 令他的值等于 cur1 的值, 然后插入新链表.

拷贝复杂链表
ComplexNode* CopyComplex(ComplexNode* head); 

复杂链表就是多了一个 random 指针, 指向任意结点, 或者为空
思路: 把每个结点的后面都插入一个自身节点, 创建新结点, 拷贝它前一个结点的值, 并插入其后, 这样每个拷贝结点的 random 指向的肯定是 它前面那个结点 random 指向结点的下一个结点.


C语言代码实现

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

#define DataType int
#define TESTHEAD printf("=====%s=====\n", __FUNCTION__);

typedef struct Node
{
    DataType data;
    struct Node* next;
    struct Node* random;
}linklist, *plinklist;

//创建新结点
plinklist CreateNode()
{
    plinklist Node = (plinklist)malloc(sizeof(linklist));
    Node->random = NULL;
    return Node;
}
//销毁结点
void DestoryNode(plinklist Node)
{
    free(Node);
    Node = NULL;
}
//链表初始化
void LinkListInit(plinklist* head)
{
    *head = CreateNode();
    (*head)->next = NULL;
    (*head)->random = NULL;
    printf("初始化完成\n");
}
//链表的插入(尾插)
void LinkListPushBack(plinklist* head, DataType data)
{

    plinklist Node;
    plinklist temp;
    if((*head)->next == NULL)
    {
        Node = CreateNode();
        Node->data = data;
        (*head)->next = Node;
        Node->next = NULL;
    }
    else if((*head)->next)
    {
        temp = *head;
        while(temp->next)
        {
            temp = temp->next;
        }

        Node = CreateNode();
        Node->data = data;
        temp->next = Node;
        Node->next = NULL;
        temp = Node;
    }
}
//顺序打印链表
void LinkListPrint(plinklist* head)
{
    if((*head)->next == NULL)
    {
        printf("空链表\n");
        return ;
    }
    plinklist temp = (*head)->next;
    while(temp)
    {
        if(temp->random == NULL)
        {
            printf("[%d|%9p|NULL]\n", temp->data, temp->next);
        }
        else
        {
            printf("[%d|%9p][%d]\n", temp->data, temp->next, temp->random->data); 
        }
        temp = temp->next;
    }      
}
//逆序打印单链表
void LinkListReversePrint(plinklist* head)
{
    if(*head == NULL)
      return ;
    if((*head)->next)
    {
        LinkListReversePrint(&((*head)->next));
    }
    printf("[%d|%9p]\n", (*head)->data, (*head)->next);
}
//不允许遍历链表, 在 pos 之前插入 
//思路:先在pos后插入,然后和pos的值交换
void LinkListInsertBeforePos(plinklist* head, plinklist pos, DataType data)
{
    if(head == NULL)
    {
        printf("非法输入\n");
        return ;
    }
    if((*head) == NULL)
    {
        printf("空链表\n");
        return ;
    }
    plinklist temp = *head;
    plinklist Node = CreateNode();
    Node->data = data;
    Node->next = pos->next;
    pos->next = Node;
    int tmp = Node->data;
    Node->data = pos->data;
    pos->data = tmp;
}
//单链表逆置
void LinkListReverse(plinklist* head)
{
    if(head == NULL) 
    {
        printf("非法输入\n");
        return ;
    }
    if((*head)->next == NULL) 
    {
        printf("空链表\n");
       
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值