C语言手撕实战代码_单链表

C语言手撕实战代码_单链表

题目清单:

单链表习题
1.使用头插法构建带头结点的单链表
2.使用尾插法构建带头结点的单链表
3.在第i个数据结点前插入元素e
4.设计算法高效查找带头单链表倒数第m个位置(m个正整数)的结点并输出该结点值
5.已知指针La和Lb分别指向两个无头结点的单链表。编写函数完成从La中删除第j个元素开始的共len个元素,并将这len个元素插入到表Lb中第j个元素之前
6.设单链表表头指针为L,节点数据域为字符。设计时间复杂度最低的算法判断前n/2个字符是否与后n/2字符依次相同,例如:xyx和xyxy中前一半字符与后一半字符是否相同

1.使用头插法构建带头结点的单链表

构建大体思路,
写一个函数构建单链表(链表引用头,int数组,数组长度)
也就是说通过先读入数组,然后再构建单链表

#include<stdio.h>
#include<stdlib.h>
typedef  int ElemType;
typedef struct LinkNode
{
    ElemType data;
    struct LinkNode* next;
    
}LinkNode,*LinkList;

void creat_linklist_byinserthead(LinkList &L,int enterArra[],int enterArraLength)
{
    //先定义头结点
    L=(LinkNode *)malloc(sizeof(LinkNode));
    L->next=NULL;
    
    //循环头插结点
    int index=0; //第一个数组下标
    while(index<enterArraLength)
    {
        LinkNode *p=(LinkNode *)malloc(sizeof(LinkNode));
        p->data= enterArra[index++];
        p->next=L->next;
        L->next=p;
    }
}

void printLink(LinkList L)
{
    LinkList p=L->next;
    while (p) {
        printf("%d->",p->data);
        p=p->next;
    }
    printf("NULL\n");
}
int main()
{
    LinkList L=NULL;  //声明一个头指针
    int enterArra[100]={0};
    int enterlength=0;
    printf("请输入数组序列:\n");
    int enterData=999999;//读入结束标记是999999,当读入999999时,输入就结束,循环就结束
    while (scanf("%d",&enterData)&&999999>enterData) {
        enterArra[enterlength++]=enterData;
    }             //结束数组的读入
    creat_linklist_byinserthead(L, enterArra, enterlength);
    printLink(L);
    
    printf("\n");
    return 1;
}

在这里插入图片描述

2.使用尾插法构建带头结点的单链表

void creat_linklist_byinserttail(LinkList &L,int enterArra[],int enterArraLength)
{
    //先定义头结点
    L=(LinkNode *)malloc(sizeof(LinkNode));
    L->next=NULL;
    
    //循环尾插结点
    int index=0; //第一个数组下标
    LinkList tail=L;
    while(index<enterArraLength)
    {
        LinkNode *p=(LinkNode *)malloc(sizeof(LinkNode));
        p->data= enterArra[index++];
        tail->next=p;
        tail=p;
    }
    tail->next=NULL;
}

3.在第i个数据结点前插入元素e

void insert_before_i(LinkList &L,int k,int e)  //在第k个元素前插入,移动k-1下就插入
{
    LinkNode *p=L;
    for(int i=0;i<k-1;i++)
    {
        p=p->next;
    }            // 找到插入点
    LinkNode *x=(LinkNode*)malloc(sizeof(LinkNode));
    x->data=e;
    x->next=p->next;
    p->next=x;
}

在这里插入图片描述

4.设计算法高效查找带头单链表倒数第m个位置(m个正整数)的结点并输出该结点值

void getdata(LinkList L,int m)
{
    LinkNode *cur=L->next;
    LinkNode *pre=L->next;
    
    while (m--) {
        cur=cur->next;
    }
    
    while(cur!=NULL)
    {
        pre=pre->next;
        cur=cur->next;
    }
    printf("元素是%d\n",pre->data);
}

在这里插入图片描述

5.已知指针La和Lb分别指向两个无头结点的单链表。编写函数完成从La中删除第j个元素开始的共len个元素,并将这len个元素插入到表Lb中第j个元素之前

分析:
本题中值得积累的点,在于人为加入头结点,来进行头结点的让控制链表的操作更简单。
至于这道题就是按步骤来就行

主函数

//定义两个现成的单链表La和Lb
    int a[8]={1,2,3,4,5,6,7,8};
    int b[8]={9,10,11,12,13,14,15,16};
    LinkList La=NULL;
    LinkList Lb=NULL;
    creat_linklist_byinserttail(La, a, 8);
    creat_linklist_byinserttail(Lb, b, 8);
    printLink(La);
    printLink(Lb);
    operator_linklist(4, 3, La, Lb);
    printLink(La);
    printLink(Lb);

自定义函数

void operator_linklist(int j,int len,LinkList &La,LinkList &Lb)
{
    //首先是从给La和Lb加上头结点
    LinkNode* headLa=(LinkNode*)malloc(sizeof(LinkNode));
    LinkNode* headLb=(LinkNode*)malloc(sizeof(LinkNode));
    headLa->next=La;
    headLb->next=Lb;
    
    int count=j; //
    LinkNode* p1=headLa;
    //找到La第j个元素指向位置
    while (count--) {
        p1=p1->next;
    }    //循环结束后此时的p1指向第j个元素的前一个元素
    count=len;
    LinkNode* p2=p1;
    while(count--)
    {
        p2=p2->next;
    }             // p2指向删除链上的最后一个元素
    printf("第%d个元素的前一个元素是%d\n",j,p1->data);
    printf("删除链的最后一个元素是%d\n",p2->data);
   
    LinkNode* p3=p1;  p1=p1->next; //p1指向删除链的第一个元素,p2指向删除链的最后一个元素,p3指向删除链的前一个元素
    p3->next=p2->next;  //完成La的断链
    p2->next=NULL;
    
    //记录L的第j个元素的前一个元素,和第j个元素
      count=j-1;
    LinkNode* p4=Lb;
    while (count--) {
        p4=p4->next;
    }    //循环结束后此时的p4指向第j个元素的前一个元素
    LinkNode* p5=p4->next;  //p5记录指向j个元素
    p4->next=p1;
    p2->next=p5;
    free(headLa);
    free(headLb);
    
}

在这里插入图片描述

6.设单链表表头指针为L,节点数据域为字符。设计时间复杂度最低的算法判断前n/2个字符是否与后n/2字符依次相同,例如:xyx和xyxy中前一半字符与后一半字符是否相同

思路:
利用快慢指针找到中间结点,然后依次从前往后对比就完了

7.La和Lb按值非递减,归并La和Lb,得到新的单链表Lc,使得Lc也按值非递减且不含重复元素,并占用原来的空间

思路:
La和Lb从头开始遍历,用尾插法建立单链表,然后利用尾插法建立单链表Lc,若元素和Lc表尾元素不同,加入Lc,相同就下一个。

void no_repeat_insert(LinkList &tailLc, LinkNode *&pnode)
{
    // 判断元素是否重复, 使用尾插法插入
    if (tailLc == NULL || tailLc->data != pnode->data)
    {
        tailLc->next = pnode;
        tailLc = tailLc->next;  // 尾插法,一直指向表尾
    }
    pnode = pnode->next;  // 后移
}

void combineSortedLink(LinkList &Lc, LinkList &La, LinkList &Lb)
{
    LinkNode *pcurLa = La;
    LinkNode *pcurLb = Lb;
    LinkNode *tailLc = Lc;

    // 只有在两个链表都不为空的情况下,才能进行比较合并
    while (pcurLa != NULL && pcurLb != NULL)
    {
        if (pcurLa->data <= pcurLb->data)
        {
            no_repeat_insert(tailLc, pcurLa);
        }
        else
        {
            no_repeat_insert(tailLc, pcurLb);
        }
    }

    // 如果La有剩余,继续插入
    while (pcurLa != NULL)
    {
        no_repeat_insert(tailLc, pcurLa);
    }

    // 如果Lb有剩余,继续插入
    while (pcurLb != NULL)
    {
        no_repeat_insert(tailLc, pcurLb);
    }

    // 最后将链表末尾置空,确保链表的完整性
    tailLc->next = NULL;
}

本题积累,
1.用函数的过程中,别忘了&,指针变量也要&,才能进行实际操作。
2.pcurLb != NULL和!pcurLb作为while循环的条件,意义不同
pcurLb != NULL是说它不是空指针
!pcurLb意思是只要pcurLb是空的就进行循环,完全是相反的语句。

8.带头单链表中所有元素的数据值按递增顺序排列,删除链表中大于min且小于max的元素

设计数据:
1.全部小于min或全部大于max,返回原先链表
2.有大于min小于max的部分,删除后返回

9.设计一个算法,判断La是否为Lb的子链,子链的定义为:La中的从前到后的所有节点的数据域都按照原有顺序出现在Lb上

在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐要考研

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值