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