C语言链表学习记录

1.什么是链表

链表是一种数据结构,是一种存放数据的思想,也是数据的集合

2.链表与数组的区别

数组的特点:存放元素地址空间连续,不方便增、删、改、查

int array[10];
int array2[3]={1,2,3};

链表:除了地址空间连续也方便增、删、改、查

typedef struct student{
    int num;
    struct student* next;
}stus,*pstus;

int main(){
    stus k1={1,NULL};
    stus k2={2,NULL};
    stus k3={3,NULL};
    k1.next=&k2;//通过指针使地址连续
    k2.next=&k3;
    return 0;
}

3.链表的静态添加与动态遍历

静态添加链表 :定义一个结构体变量,使上个地址的尾巴指向新地址

int main(){
    stus k1={1,NULL};
    stus k2={2,NULL};
    stus k3={3,NULL};
    stus k4={4,NULL};
    k1.next=&k2;//通过指针使地址连续
    k2.next=&k3;
    k3.next=&k4;//添加链表k4
    return 0;
}

动态遍历整个链表,输出链表整个元素

typedef struct student{
        int num;
        struct student* next;
}stus,*pstus;
void printLink(pstus head){
    pstus p=head;//定义一个新的指针,方便遍历
    while(p!=NULL){
        printf("%d ",p->num);//打印链表
        p=p->next;//每执行一次,需要指向链表的下一个地址
    }
        putchar('\n');//结束打印一个换行,好看点
}
int main (){
    stus k1={1,NULL};
    stus k2={2,NULL};
    stus k3={3,NULL};
    stus k4={4,NULL};
    k1.next=&k2;
    k2.next=&k3;
    k3.next=&k4;
    printLink(&k1);//定义的是指针,需要传入地址
}

在Linux中输出结果:成功遍历1 2 3 4

 4.链表遍历中的p=p->next

解释:为什么要用p=p->next

        k1.next=&k2;

        k2.next=&k3;

        k3.next=&k4;

       此时k1 k2 k3 k4 的地址连续,每输出一个链表元素,需要其指向下一个节点的地址

5.统计链表节点个数及链表查找

#include <stdio.h>
struct workers{//定义一个结构体
        int datas;
        struct workers* point;
};
void printWorkes(struct workers* next){//遍历整个整个链表
        while(next!=NULL){
                printf("%d  ",next->datas);
                next=next->point;
        }
                putchar('\n');
}
int totalPoint(struct workers* next){//计算节点数
        int cnt=0;
        while(next!=NULL){
                next=next->point;
                cnt+=1;
        }
                return cnt;//返回节点数
}
int  findElement(struct workers* next,int num ){//查找数据
           while(next!=NULL){
           while(next!=NULL){
                if(next->datas==num){//如果查找的节点与当前遍历的节点相同,返回 1
                        return 1;
                 }
                     next=next->point;
                }
                        return 0;
}
int main(){
        int ret;
        struct workers k1={1,NULL};
        struct workers k2={2,NULL};
        struct workers k3={3,NULL};
        struct workers k4={4,NULL};
        struct workers k5={5,NULL};
        k1.point=&k2;
        k2.point=&k3;
        k3.point=&k4;
        k4.point=&k5;
        printWorkes(&k1);//遍历整个链表的节点
        ret=totalPoint(&k1);
        printf("totalPoint=%d\n",ret);
        ret=findElement(&k1,5);//查找数据,这里是查找5
        if(ret==1){
           printf("找到了,ret=%d\n",ret);
        }
        else{
                printf("没有找到,ret=%d\n",ret);
        }
        return 0;
}

运行结果:成功找到 5

 6.从指定节点后方插入新节点

#include <stdio.h>
#include <string.h>//对字符串操作加入该头文件
typedef struct dormitory{//定义结构体
        char array[100];
        struct dormitory* next;
}dosr,*pdors;
void printName(pdors point){//打印名字
        pdors p=point;
        while(p!=NULL){
                printf("%s ",p->array);
                p=p->next;
        }
                putchar('\n');
}
int insertName(pdors point,char name[10],pdors newName){//插入字符串
        int cnt=0;
        printf("oldname=%s\n",name);
        printf("point->array=%s\n",point->array);
        while(point!=NULL){
                if(strcmp(point->array,name)==0){//字符串比较要用strcmp
                        newName->next=point->next;//指定节点后方插入节点算法
                        point->next=newName;
                        return 1;
                }
                point=point->next;
                cnt+=1;
        }
                printf("cnt=%d \n",cnt);//计算节点数
                return 0;
}

int main(){
        dosr k1={"张三",NULL};
        dosr k2={"李四儿",NULL};
        dosr k3={"王二麻子",NULL};
        dosr k4={"燕双鹰",NULL};
        dosr k5={"Ultrman",NULL};
        k1.next=&k2;
        k2.next=&k3;
        k3.next=&k4;
        k4.next=&k5;
        printName(&k1);
        int ret=0;
        char str[10];
        dosr k6={"Dugad",NULL};
        ret=insertName(&k1,strcpy(str,"燕双鹰"),&k6);//接受返回值,并判断是否插入成功
        if(ret==1){
                printf("%s插入成功\n",k6.array);
                printName(&k1);
        }
        else{
                printf("插入不成功\n");
        }

        return 0;
}

运行结果:在燕双鹰后面插入 dugad (迪迦)

7.从指定节点前方插入新节点

#include <stdio.h>
#include <string.h>
typedef struct books{//定义结构体
        char names[100];
        struct books* next;
}book,*pbook;
void printLink(pbook point){//打印书名链表
        pbook p=point;
        while(p!=NULL){
                printf("%s ",p->names);
                p=p->next;
        }
                putchar('\n');
}
pbook printInsertHead(pbook point,char name[100],pbook newName){//链表头插法
        pbook p=point;
        printf("newName=%s\n",newName->names);
        if(strcmp(p->names,name)==0){//判断插入的是否是链表的第一个节点
                newName->next=p;
                return newName;//返回的节点需从第一个节点开始
        }
        while(p->next!=NULL){//判断链表头节点之后的元素
                if(strcmp(p->next->names,name)==0){
                        newName->next=p->next;//前插法算法
                        p->next=newName;
                        printf("Fingding!\n");
                        return point;
                }
                        p=p->next;
        }
                        printf("Not Fingding!\n");
                        return point;
}
int main(){//链表前插法
        book k1={"程序员教程",NULL};
        book k2={"嵌入式Linux系统开发",NULL};
        book k3={"信号与系统",NULL};
        book k4={"我有一杯酒,可以慰风尘",NULL};
        k1.next=&k2;
        k2.next=&k3;
        k3.next=&k4;
        pbook head=&k1;
        printLink(head);
        book k5={"我有故事,你有酒吗",NULL};
        char strName[100];
        char strName[100];
        pbook TOU=NULL;
        TOU=printInsertHead(head,strcpy(strName,"程序员教程"),&k5);
        printf("TOUName=%s\n",TOU->names);
        printLink(TOU);
        return 0;
}

运行结果:在 程序员教程 前面插入 我有故事你有酒吗

8.删除链表节点

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct honor{//定义结构体
        char name[100];
        struct honor* next;
}ono,*pono;
void printLink(pono point){遍历链表
        pono p=point;
        while(p!=NULL){
                printf("%s ",p->name);
                p=p->next;
        }
                putchar('\n');
}
pono printDeleteName(pono point,char delName[100]){
        pono p=point;
        if(strcmp(p->name,delName)==0){//删除第一个名字
                point=point->next;
                free(p);
                return point;
        }
        while(p->next!=NULL){//遍历第一个名字后面的地址
                if(strcmp(p->next->name,delName)==0){//字符串比较用strcmp
                                p->next=p->next->next;删除后面节点算法
                                printf("删除成功!\n");
                                return point;
                }
                                p=p->next;
        }
                                printf("删除不成功\n");
                                return point;
}
int main(){
//      ono k1={"卧槽",NULL};
        pono k1=(pono)malloc(sizeof(ono));
        ono k2={"鲁班七号",NULL};
        ono k3={"梦琪",NULL};
        ono k4={"上官婉儿",NULL};
        strcpy(k1->name,"卧槽");
        printf("k1->name=%s\n",k1->name);
        k1->next=&k2;
        k2.next=&k3;
        k3.next=&k4;
        pono head=NULL;
        head=k1;
        printLink(head);
        char deleteName[100];
        pono delName=NULL;
        delName=printDeleteName(head,strcpy(deleteName,"上官婉儿"));//删除上官婉儿
        printLink(delName);//打印删除后的名字
        return 0;
}

运行结果:删除上官婉儿

9.动态链表之头插法

#include <stdio.h>
#include <stdlib.h>//分配地址空间所需的头文件
typedef struct books{//定义结构体
        int num;
        struct books* next;
}book,*pbook;
pbook insertHead(pbook head,pbook new){//创造新节点函数
        if(head==NULL){
                head=new;//如果头结点为空,把new的地址赋给head,也可以说让head指向new的地址
        }else{
                new->next=head;//让new的下一个地址指向head
                head=new;
        }
        return head;
}
pbook creatLink(pbook head){//头插法创建链表
        pbook new=NULL;//使其指向NULL,不让其成为野指针
        while(1){
        new=(pbook)malloc(sizeof(book));//对新定义的结构体指针分配空间
        printf("please insert a new point:");
        scanf("%d",&new->num);//输入你要创造的链表节点
        if(new->num==0){//如果输入0,创造节点停止
                printf("End!\n");
                return head;//使返回值始终指向链表的头节点
        }
        head=insertHead(head,new);//调用头插法节点函数
        }
}
void printLink(pbook head){//打印节点
        pbook p=head;
        while(p!=NULL){
                printf("%d ",p->num);
                p=p->next;
        }
                putchar('\n');
}

int main(){
        pbook p=NULL;
        //p=insertHead(p);
        p=creatLink(p);
        printLink(p);
        return 0;
}

运行结果: 有点像 栈 先进先出

10.动态链表尾插法

#include <stdio.h>
#include <stdlib.h>
typedef struct workers{
        int num;
        struct workers* next;
}work,*pwork;
pwork insertBehindHead(pwork head,pwork new){
        pwork p=head;
        if(p==NULL){
                head=new;
                return head;
        }
        while(p->next!=NULL){//尾插法比较简单,每次使插入链表的新节点向后移就行了
                p=p->next;
        }
                p->next=new;
                return head;//使返回值始终指向头结点
}
pwork creatLinkBehind(pwork head){
        pwork new=NULL;
        while(1){
        new=(pwork)malloc(sizeof(work));//分配地址空间
        printf("please insert a new numbers:");
        scanf("%d",&new->num);
        if(new->num==0){
                printf("Ending!\n");
                return head;
        }
        head=insertBehindHead(head,new);//调用尾插法函数
        }
}
void printLink(pwork head){
        pwork p=head;
        while(p!=NULL){
                printf("%d ",p->num);
                p=p->next;
        }
                putchar('\n');
}
int main(){
        pwork p=NULL;
        p=creatLinkBehind(p);//动态链表尾插法
        printLink(p);//遍历链表
        return 0;
}

运行结果:成功啦

11.总结

个人觉得学习这个链表得画几个圈圈,画得几次就行了,算法不是很难

12.来个小型的综合版

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct books{
        char  name[100];
        struct books* next;
}book,*pbook;
pbook dynamicBehindBookName(pbook head,pbook new){
        pbook p=head;
        if(p==NULL){
                head=new;
                return head;
        }
        while(p->next!=NULL){
                p=p->next;
        }
                p->next=new;
                return head;
}
pbook insertBookName(pbook head){
        pbook new=NULL;
        while(1){
                new=(pbook)malloc(sizeof(book));
                printf("please insert new2 name:");
                scanf("%s",new->name);
                if(strcmp(new->name,"0")==0){
                        printf("Ending!\n");
                        return head;
                }
        head=dynamicBehindBookName(head,new);
        }
pbook deleteInsertLink(pbook head,char name[100]){
        pbook p=head;
        if(strcmp(p->name,name)==0){
                head=head->next;
                free(p);
                printf("successfully delete head!\n");
                return head;
        }       
        while(p->next!=NULL){
                if(strcmp(p->next->name,name)==0){
                        p->next=p->next->next;
                        printf("sucessfully delete the link of elements!\n");
                        return head;    
                }       
                        p=p->next;
        }               
                        printf("Not sucessful delete!\n");
                        return head;
}                       
pbook dynamicInsertBookName(pbook head,pbook new){
        pbook p=head;
        if(p==NULL){
                head=new;
        }
        else{
                new->next=head;
                head=new;
        }
        return head;
}
pbook insertForntName(pbook head){
        pbook p=head;
        pbook new=NULL;
        while(1){
                new=(pbook)malloc(sizeof(book));
                printf("please insert a new book name:");
                scanf("%s",new->name);
                if(strcmp(new->name,"0")==0){
                        printf("退出动态插入字符串链表\n");
                        return head;
                }
                head=dynamicInsertBookName(head,new);
        }
}
void printLink(pbook head){
        pbook p=head;
        while(p!=NULL){
                printf("%s ",p->name);
                p=p->next;
        }
                putchar('\n');
}
int main(){
        //复习4,动态前and behind 插入链表元素
        pbook head=NULL;
        head=insertForntName(head);
        printLink(head);
        pbook head2=NULL;
        head2=insertBookName(head2);
        printLink(head2);
        //review 5,delete the head of link or others element
        pbook p=NULL;
        char newName[100];
        p=deleteInsertLink(head,strcpy(newName,"ouliang"));
        printLink(p);
        return 0;
}
  

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct students{
        int num;
        struct students* next;
}stus,*pstus;
int printPointNum(pstus head){
        pstus p=head;
        int cnt=0;
        while(p!=NULL){
                cnt+=1;
                p=p->next;
        }
                return cnt;
}
pstus insertLinkNumber(pstus head,int number,pstus new){
        pstus p=head;
        while(p!=NULL){
                if(p->num==number){
                        new->next=p->next;
                        p->next=new;
                        return head;
                }
                p=p->next;
        }
}
void printLink(pstus head){
        pstus p=head;
        while(p!=NULL){
                printf("%d ",p->num);
                p=p->next;
        }
                putchar('\n');
}
int main(){
        stus k1={1,NULL};
        stus k2={2,NULL};
        stus k3={3,NULL};
        stus k4={4,NULL};
        k1.next=&k2;
        k2.next=&k3;
        k3.next=&k4;
        pstus head=&k1;
        printLink(head);//复习1,输出链表
        stus k5={5,NULL};
        pstus point=NULL;
        point=insertLinkNumber(head,4,&k5);//复习2,在链表任意位置后面插入数字
        printLink(point);
        int set=0;
        set=printPointNum(point);//复习3,节点数统计
        printf("节点数cnt=%d\n",set);
        return 0;
}

运行结果:无 ,相信我能看懂的!

啊哈C

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值