C语言单链表初识

单链表初探

——链表的节点其实是一个结构体,里边分为两部分:

typedef struct _node
{
    int value;
    struct _node *next;
}Node,*LinkList;
  • 一部分为数据部分,可以是任何的数据类型(int、double、float、char、char*、[]...)
        int value;
    我们引出链表就是为了储存数据(大量,少量的data数组就ojbk),这部分就是其实也就是我们要储存的data。
  • 另一部分就是一个比较有意思的东西了struct pointer ,It's amazing;→不要走开哦
struct _node *next;
  • ←节点的结构,V是data,*是结构指针。
  • 其实链表的出现是弥补数组的不足的,在我们实际开发中,我们用数组的时候,数组的大小是我们原先设定好的,这就很具有局限性了,我们数据很多的时候,数组往往是满足不了我们的需求的,于是前辈的大佬们就想办法解决这一问题,其实,在链表出现之前出现的是动态数组。前辈们想在开发过程中,设计一个能变长的数组,来满足实际开发的需要。这是另一个故事...
  • 接下来实际应用链表

操作单链表


一般我们初始一个头指针作为第一个节点,然后其head->next所指向NULL来表示一条完整的链(有头有尾),那么创建这个链子就有两种方法了,一种从头往后插入数据,一种从尾插入,称为头插法和尾插法。

  • 头插法创建单链表
void CreateList_H(LinkList head){
    LinkList p;
    int num;
    while(scanf("%d",&num),num!=-1){
        p=(LinkList)malloc(sizeof(Node));
        p->value=num;
        p->next=head->next;
        head->next=p;
    }
}

①head开始是一个空指针,head->next=NULL,所谓头插,只需把所要储存的数据接到head后边即可。

②p->next=head->next; p结构的next指针指向head结构的next指针所指的内存区域。

③然后,head->next=p;head结构的next指针指向p结构。

  • 尾插法创建单链表
void CreateList_T(LinkList head)
{
    LinkList p,rear=head;
    int num;
    while(scanf("%d",&num),num!=-1){
        p=(LinkList)malloc(sizeof(Node));
        p->value=num;
        rear->next=p;
        rear=p;
    }
    rear->next=NULL;
}

①尾插法与头插相反,是与最后一个结构节点进行一系列操作。

②首先定义一个结构指针rear,用它来指向最后一节的元素,首先它指向head结构,新节点p需要插在rear后边,rear->next=p;然后将rear指向最后的p结构。

③创建完毕后,rear的next指针指向NULL,表示完整链。

  • 遍历单链表
void PrintList(LinkList head){

    LinkList p=head->next;
    while(p){
        printf("%d ",p->value);
        p=p->next;
    }
}

①声明一个指针指向head后边的第一个元素

②p不为NULL,输出p->value;

③p=p->next; p后移

  • 单链表的插入
void ListInsert(LinkList head,int i,int e){
    LinkList p,pre=head;
    int j=0;
    while(pre&&j<i-1)//找到i-1位置的元素指针
    {
        pre=pre->next;
        j++;
    }
    if(!pre||i<1){//判断所找元素位置是否存在
        printf("i的值有误!\n");
        return;
    }
    p=(LinkList)malloc(sizeof(Node));
    p->value=e;
    p->next=pre->next;
    pre->next=p;
}

①在链表中,确定新元素应该被加入到哪个节点后边,该节点成为前驱节点,用结构指针pre指向

②创建新的节点,使用p指向

③p->next=pre->next;新节点的next指针指向前驱节点的next所指

④pre->next=p;前驱节点的next指向p结构

  • 单链表的删除
void ListDelete(LinkList head,int i,int *e)
{
    LinkList p,pre=head;
    int j=0;
    while(pre&&j<i-1){
        pre=pre->next;
        j++;
    }
    if(!pre||i<1){
        printf("i值有误!!");
        return;
    }
    p=pre->next;
    pre->next=p->next;
    e=&p->value;
    free(p);
}

①定位要删除的节点p的前驱节点pre

②改变前驱节点的next指针绕过p指向p的next所指

③free函数释放p,把删除数据暂存e所指内存区

  • 单链表合并
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LEN 100

typedef struct Lnode
{
    int value;
    struct Lnode *next;
}Lnode,*LinkList;
void createlist_A(LinkList La)//头插法创建单链表La
{

    LinkList p;
    int value;
    printf("创建单链表La:\n");
    while(scanf("%d",&value)&&value!=-1)
    {
        p=(LinkList)malloc(sizeof(Lnode));
        p->value=value;
        p->next=La->next;
        La->next=p;
    }
}
void createlist_B(LinkList Lb)//头插法创建单链表Lb
{

    LinkList p;
    int value;
    printf("创建单链表Lb:\n");
    while(scanf("%d",&value)&&value!=-1)
    {
        p=(LinkList)malloc(sizeof(Lnode));
        p->value=value;
        p->next=Lb->next;
        Lb->next=p;
    }
}
void printList(LinkList Lhead)
{
    LinkList p=Lhead->next;
    while(p)
    {
        printf("%d ",p->value);
        p=p->next;
    }
    printf("\n");
}
void MergeList(LinkList La,LinkList Lb,LinkList Lc)//两个单链表合并
{
    LinkList p,q,r;
    p=La->next;q=Lb->next;
    Lc=r=La;
    while(p&&q)
    {
        if(p->value<q->value)
        {
            r->next=p;
            r=p;                       //类似尾插法创建链表
            p=p->next;
        }
        else if(p->value<q->value)
        {
            r->next=q;
            r=q;
            q=q->next;
        }
        else if(p->value==q->value)
        {
            r->next=p;
            r=p;
            p=p->next;
            q=q->next;
        }
    }
    while(p)
    {
        r->next=p;
        r=p;
        p=p->next;
    }
    while(q)
    {
        r->next=q;
        r=q;
        q=q->next;
    }
    r->next=NULL;
    printf("合并后链表Lc的内容为:\n");
    printList(Lc);

}
int main(){
LinkList La=NULL,Lb=NULL,Lc=NULL;
Lc=(LinkList)malloc(sizeof(Lnode));
Lc->next=NULL;
La=(LinkList)malloc(sizeof(Lnode));
La->next=NULL;
Lb=(LinkList)malloc(sizeof(Lnode));
Lb->next=NULL;
createlist_A(La);

createlist_B(Lb);
printf("链表La的内容为:\n");
printList(La);
printf("链表La的内容为:\n");
printList(Lb);
MergeList(La,Lb,Lc);
return 0;
}

①创建链表La,Lb,Lc,初始化起始结点不能在局部函数中写,写在main函数中。

②用指针Lc创建一个新的链表作为合并的链表。不需要另建新的表的结点空间,而只需将原来两个链表中结点之间的关系解除,重新按元素值非递减的关系将所有结点链接成一个新的链表即可。

⭐头插法创建的链表是倒序的,先输入的在后边结点。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值