C语言单向动态链表程序,实现链表的建立,合并,重新排序,链表元素的插入与删除,以及根据元素成员的值进行元素删除。
2015-10-01 16:09
976 查看
//
// LinkedList.c
// C exercise
//
// Created by y liu on 15/10/1.
// Copyright © 2015年 y liu. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LEN sizeof(struct Student)
int n;
//外部变量n,用于创建链表时记录元素数量
int L1,L2;
//记录各个链表的元素数量
struct Student
//利用结构体创建一个链表元素
{
int num;
float score;
struct Student * next;
};
struct Student * creat2()
//链表建立函数,此函数将会返回一个链表头地址
{
printf("Creat a LinkedList.Enter 0 to end the process\n");
struct Student *head;
struct
Student *p1,*p2;
//建立一个链表,我们需要两个指针进行各节点的链接
n=0;
p1=p2=(struct
Student *)malloc(LEN);
//开辟了第一个链表元素的空间
scanf("%d,%f",&p1->num,&p1->score);
//给第一个链表元素的成员赋值
head=NULL;
while(p1->num!=0)
//如在给链表元素第一个成员赋值时输入0并回车则结束函数
{
n=n+1;
//链表节点计数
if(n==1)head=p1;
//head指针获取链表头地址
else p2->next=p1;
//最后一个链表元素的尾部指针连接新开辟的链表元素的地址
p2=p1;
//p2指向下一个链表元素,准备下一个节点的链接
p1=(struct
Student*)malloc(LEN);
//p1指针脱离链表开辟新空间
scanf("%d,%f",&p1->num,&p1->score);
//给每个链表元素的成员赋值
}
p2->next=NULL;
//最后一个链表元素的指针指向空值
return(head);
//返回链表头地址
}
void print(struct
Student *head)
//链表输出函数
{
struct Student *p;
printf("\nNow,These records are:\n");
p=head;
if(head!=NULL)
{
do
{
printf("%d%5.1f\n",p->num,p->score);
p=p->next;
//p不断寻找下一个链表元素
}while(p!=NULL);
}
}
void del(struct
Student *head,int L)
//链表删除函数
{
int delete;
//将要删除的链表元素
struct Student *p,*temp;
//指针p用于遍历链表元素,temp用于链接被删除元素的前后两个元素
printf("\nWhich member of LinkedList you want to delete?\n");
scanf("%d",&delete);
p=head;
temp=head;
for(int i=1;i<delete;i++)
//假如我们要删除第五个链表元素,temp必须指向第四个元素,p指向第五个元素,
{
//这样,p的尾部指针就等于第六个元素的地址,4与6可以链接
if(i==(delete-1))
{
temp=p;
//temp指向被删除元素的前一个元素
}
p=p->next;
//p指向即将被删除的元素
}
temp->next=p->next;
// 被删除元素的前一个元素的尾部指针指向被删除元素的下一个元素,被删除元素脱离链表
free(p);
//释放被删除的链表元素内存
L=L-1;
//计数器减一
print(head);
}
void insert(struct
Student *head,int L)
//链表插入函数,思路与删除函数类似
{
int insertnum;
//在指定的链表元素后加入一个新元素
struct Student *p,*temp,*new;
printf("\nAfter which point you want to insert?\n");
scanf("%d",&insertnum);
p=head;
temp=head;
for(int i=1;i<=insertnum;i++)
//假如我们要在第五个链表元素后插入,temp必须指向第五个元素,p指向第六个元素,
{
if(i==(insertnum))
{
temp=p;
//temp指向将要插入元素的前一个元素
}
p=p->next;
//p指向将要插入元素的后一个元素
}
new=malloc(LEN);
//为即将插入的元素开辟内存,new既是将要插入的元素
temp->next=new;
//插入元素的前一个元素的尾部指针指向插入的元素
new->next=p;
//插入元素指针指向后一个元素
printf("\nPlease enter the number and the score.\n");
scanf("%d,%f",&new->num,&new->score);
//新元素成员赋值
L=L+1;
print(head);
}
void combine(struct
Student *heada,struct
Student *headb,int L1,int L2)
//链表合并并重新排列顺序函数
{
struct
Student *p[L1+L2];
//建立一个指针数组记录两个链表的各个元素地址
p[0]=heada;
for(int i=0;i<L1;i++)
//遍历并复制第一个链表的各元素地址
{
p[i+1]=p[i]->next;
}
p[L1]=headb;
for(int i=0;i<L2;i++)
//遍历并复制第二个链表的各元素地址
{
p[L1+i+1]=p[L1+i]->next;
}
p[L1+L2-1]->next=p[L1+L2]=NULL;
struct Student *temp;
temp=malloc(LEN);
for(int i=0;i<L1+L2;i++)
//指针数组重新排序
{
for(int j=i+1;j<L1+L2;j++)
{
if(p[i]->num>p[j]->num)
//根据num大小进行重新排序
{
temp=p[j];p[j]=p[i];p[i]=temp;
}
}
}
for(int i=0;i<(L1+L2);i++)
//将重新排序好的链表各元素进行链接
{
p[i]->next=p[i+1];
}
p[L1+L2-1]->next=p[L1+L2]=NULL;
for(int i=0;i<(L1+L2);i++)
//输出
{
printf("%5.2d,%5.2f\n",p[i]->num,p[i]->score);
p[i]=p[i]->next;
}
}
void del2(struct
Student *heada,struct
Student*headb,int L1,int L2)
//如果第一个链表的num与第二个链表重复,则删除第一个链表的此
{
//元素
int flag=0;
struct Student *p1[L1+1];
struct Student *p2[L2+1];
p1[0]=heada;
for(int i=0;i<L1;i++)
{
p1[i+1]=p1[i]->next;
//遍历复制第一个链表各元素
}
p2[0]=headb;
for(int i=0;i<L2;i++)
{
p2[i+1]=p2[i]->next;
//遍历复制第二个链表各元素
}
p1[L1-1]->next=NULL;
p1[L1]=NULL;
p2[L2-1]->next=NULL;
p2[L2]=NULL;
int temp=-99;
//temp记录被删除的元素的序号
int temp2=0;
//temp2用来处理出现连续重复的情况
for(int i=0;i<L2;i++)
//遍历第二个链表各元素
{
for(int j=0;j<L1;j++)
//遍历第一个链表各元素
{
if(p2[i]->num==p1[j]->num)
//如果发现num重复,将分以下4种情况区别处理
{
if(j==temp+1)
//3,如果出现连续重复,temp2+1,为了一直返回操作最后一个未重复元素的尾部指针指向下一
{
//元素地址
temp2++;
}
if(j!=temp+1)
//如果无连续重复情况,temp2归0
{
temp2=0;
}
if(j==0||flag)
//1,如果是第一个链表的第一个元素,链表头指向第二个元素并直接开始第二次循环
{
p1[j]=p1[j]->next;
flag=1;
//4,特殊情况,从第一个元素开始出现连续重复,开启开关,当前元素尾部指针直接
continue;
//指向下一个元素,并直接开始下一次循环
}
p1[j-1-temp2]->next=p1[j+1];
//2,当前元素前一个元素的尾部指针指向当前元素的后一个元素的地址,当前元素脱离链表
temp=j;
//temp记录被删除元素序号
}
flag=0;
//特殊情况关闭
}
}
while(p1[0]!=0)
//输出
{
printf("%5.2d,%5.2f\n",p1[0]->num,p1[0]->score);
p1[0]=p1[0]->next;
}
}
void del3(struct
Student *heada,int L)
//根据指定条件删除链表元素
{
int flag;
int delete;
struct Student *p,*temp;
p=heada;
printf("\nWhich num you want to delete?\n");
scanf("%d",&delete);
for(int i;p->num;i++)
//先处理一种特殊情况,既第一个链表元素要被删除
{
if(p->num!=delete)
{
break;
}
else
{
p=p->next;
//如出现此情况,链表头直接指向下一个元素
}
}
heada=temp=p;
//temp指向当前第一个元素
for(int i;p->next;i++)
{
flag=0;
//flag 处理需要连续删除的情况
p=p->next;
//遍历链表各元素
if(p->num==delete)
//如果发现元素符合指定删除条件,前一个元素尾部指针指向下一个元素地址,连续删除开关打开
{
flag=1;
temp->next=p->next;
}
if(!flag)
{
temp=p;
//temp永远记录最后一个未被删除的元素
}
}
print(heada);
}
int main()
{
struct Student * creat2(void);
//各函数声明
void print(struct
Student *);
void del(struct
Student *,int);
void insert(struct
Student *,int);
void combine(struct
Student *,struct
Student *,int,int);
void del2(struct
Student *,struct
Student*,int,int);
void del3(struct
Student*,int);
struct Student *heada,*headb;
heada=creat2();
//生成一个链表
L1=n;
headb=creat2();
//生成第二个链表
L2=n;
int choice;
printf("What do you want?\n1:print the LinkedList\n2:delete a member of the LinkedList a\n3:insert a member to the LinkedList a\n4:comine the two LinkedLists
and reform them according to 'num'\n5:delete the members of LinkedList a if that are same as those of LinkedList b\n6:delete the members of LinkedList a with the certain 'num'\n");
scanf("%d",&choice);
switch(choice)
{
case 1:print(heada);break;
//调用各函数
case 2:del(heada,L1);break;
case 3:insert(heada,L1);break;
case 4:combine(heada,headb,L1,L2);break;
case 5:del2(heada,headb,L1,L2);break;
case 6:del3(heada,L1);break;
}
return 0;
}
// LinkedList.c
// C exercise
//
// Created by y liu on 15/10/1.
// Copyright © 2015年 y liu. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LEN sizeof(struct Student)
int n;
//外部变量n,用于创建链表时记录元素数量
int L1,L2;
//记录各个链表的元素数量
struct Student
//利用结构体创建一个链表元素
{
int num;
float score;
struct Student * next;
};
struct Student * creat2()
//链表建立函数,此函数将会返回一个链表头地址
{
printf("Creat a LinkedList.Enter 0 to end the process\n");
struct Student *head;
struct
Student *p1,*p2;
//建立一个链表,我们需要两个指针进行各节点的链接
n=0;
p1=p2=(struct
Student *)malloc(LEN);
//开辟了第一个链表元素的空间
scanf("%d,%f",&p1->num,&p1->score);
//给第一个链表元素的成员赋值
head=NULL;
while(p1->num!=0)
//如在给链表元素第一个成员赋值时输入0并回车则结束函数
{
n=n+1;
//链表节点计数
if(n==1)head=p1;
//head指针获取链表头地址
else p2->next=p1;
//最后一个链表元素的尾部指针连接新开辟的链表元素的地址
p2=p1;
//p2指向下一个链表元素,准备下一个节点的链接
p1=(struct
Student*)malloc(LEN);
//p1指针脱离链表开辟新空间
scanf("%d,%f",&p1->num,&p1->score);
//给每个链表元素的成员赋值
}
p2->next=NULL;
//最后一个链表元素的指针指向空值
return(head);
//返回链表头地址
}
void print(struct
Student *head)
//链表输出函数
{
struct Student *p;
printf("\nNow,These records are:\n");
p=head;
if(head!=NULL)
{
do
{
printf("%d%5.1f\n",p->num,p->score);
p=p->next;
//p不断寻找下一个链表元素
}while(p!=NULL);
}
}
void del(struct
Student *head,int L)
//链表删除函数
{
int delete;
//将要删除的链表元素
struct Student *p,*temp;
//指针p用于遍历链表元素,temp用于链接被删除元素的前后两个元素
printf("\nWhich member of LinkedList you want to delete?\n");
scanf("%d",&delete);
p=head;
temp=head;
for(int i=1;i<delete;i++)
//假如我们要删除第五个链表元素,temp必须指向第四个元素,p指向第五个元素,
{
//这样,p的尾部指针就等于第六个元素的地址,4与6可以链接
if(i==(delete-1))
{
temp=p;
//temp指向被删除元素的前一个元素
}
p=p->next;
//p指向即将被删除的元素
}
temp->next=p->next;
// 被删除元素的前一个元素的尾部指针指向被删除元素的下一个元素,被删除元素脱离链表
free(p);
//释放被删除的链表元素内存
L=L-1;
//计数器减一
print(head);
}
void insert(struct
Student *head,int L)
//链表插入函数,思路与删除函数类似
{
int insertnum;
//在指定的链表元素后加入一个新元素
struct Student *p,*temp,*new;
printf("\nAfter which point you want to insert?\n");
scanf("%d",&insertnum);
p=head;
temp=head;
for(int i=1;i<=insertnum;i++)
//假如我们要在第五个链表元素后插入,temp必须指向第五个元素,p指向第六个元素,
{
if(i==(insertnum))
{
temp=p;
//temp指向将要插入元素的前一个元素
}
p=p->next;
//p指向将要插入元素的后一个元素
}
new=malloc(LEN);
//为即将插入的元素开辟内存,new既是将要插入的元素
temp->next=new;
//插入元素的前一个元素的尾部指针指向插入的元素
new->next=p;
//插入元素指针指向后一个元素
printf("\nPlease enter the number and the score.\n");
scanf("%d,%f",&new->num,&new->score);
//新元素成员赋值
L=L+1;
print(head);
}
void combine(struct
Student *heada,struct
Student *headb,int L1,int L2)
//链表合并并重新排列顺序函数
{
struct
Student *p[L1+L2];
//建立一个指针数组记录两个链表的各个元素地址
p[0]=heada;
for(int i=0;i<L1;i++)
//遍历并复制第一个链表的各元素地址
{
p[i+1]=p[i]->next;
}
p[L1]=headb;
for(int i=0;i<L2;i++)
//遍历并复制第二个链表的各元素地址
{
p[L1+i+1]=p[L1+i]->next;
}
p[L1+L2-1]->next=p[L1+L2]=NULL;
struct Student *temp;
temp=malloc(LEN);
for(int i=0;i<L1+L2;i++)
//指针数组重新排序
{
for(int j=i+1;j<L1+L2;j++)
{
if(p[i]->num>p[j]->num)
//根据num大小进行重新排序
{
temp=p[j];p[j]=p[i];p[i]=temp;
}
}
}
for(int i=0;i<(L1+L2);i++)
//将重新排序好的链表各元素进行链接
{
p[i]->next=p[i+1];
}
p[L1+L2-1]->next=p[L1+L2]=NULL;
for(int i=0;i<(L1+L2);i++)
//输出
{
printf("%5.2d,%5.2f\n",p[i]->num,p[i]->score);
p[i]=p[i]->next;
}
}
void del2(struct
Student *heada,struct
Student*headb,int L1,int L2)
//如果第一个链表的num与第二个链表重复,则删除第一个链表的此
{
//元素
int flag=0;
struct Student *p1[L1+1];
struct Student *p2[L2+1];
p1[0]=heada;
for(int i=0;i<L1;i++)
{
p1[i+1]=p1[i]->next;
//遍历复制第一个链表各元素
}
p2[0]=headb;
for(int i=0;i<L2;i++)
{
p2[i+1]=p2[i]->next;
//遍历复制第二个链表各元素
}
p1[L1-1]->next=NULL;
p1[L1]=NULL;
p2[L2-1]->next=NULL;
p2[L2]=NULL;
int temp=-99;
//temp记录被删除的元素的序号
int temp2=0;
//temp2用来处理出现连续重复的情况
for(int i=0;i<L2;i++)
//遍历第二个链表各元素
{
for(int j=0;j<L1;j++)
//遍历第一个链表各元素
{
if(p2[i]->num==p1[j]->num)
//如果发现num重复,将分以下4种情况区别处理
{
if(j==temp+1)
//3,如果出现连续重复,temp2+1,为了一直返回操作最后一个未重复元素的尾部指针指向下一
{
//元素地址
temp2++;
}
if(j!=temp+1)
//如果无连续重复情况,temp2归0
{
temp2=0;
}
if(j==0||flag)
//1,如果是第一个链表的第一个元素,链表头指向第二个元素并直接开始第二次循环
{
p1[j]=p1[j]->next;
flag=1;
//4,特殊情况,从第一个元素开始出现连续重复,开启开关,当前元素尾部指针直接
continue;
//指向下一个元素,并直接开始下一次循环
}
p1[j-1-temp2]->next=p1[j+1];
//2,当前元素前一个元素的尾部指针指向当前元素的后一个元素的地址,当前元素脱离链表
temp=j;
//temp记录被删除元素序号
}
flag=0;
//特殊情况关闭
}
}
while(p1[0]!=0)
//输出
{
printf("%5.2d,%5.2f\n",p1[0]->num,p1[0]->score);
p1[0]=p1[0]->next;
}
}
void del3(struct
Student *heada,int L)
//根据指定条件删除链表元素
{
int flag;
int delete;
struct Student *p,*temp;
p=heada;
printf("\nWhich num you want to delete?\n");
scanf("%d",&delete);
for(int i;p->num;i++)
//先处理一种特殊情况,既第一个链表元素要被删除
{
if(p->num!=delete)
{
break;
}
else
{
p=p->next;
//如出现此情况,链表头直接指向下一个元素
}
}
heada=temp=p;
//temp指向当前第一个元素
for(int i;p->next;i++)
{
flag=0;
//flag 处理需要连续删除的情况
p=p->next;
//遍历链表各元素
if(p->num==delete)
//如果发现元素符合指定删除条件,前一个元素尾部指针指向下一个元素地址,连续删除开关打开
{
flag=1;
temp->next=p->next;
}
if(!flag)
{
temp=p;
//temp永远记录最后一个未被删除的元素
}
}
print(heada);
}
int main()
{
struct Student * creat2(void);
//各函数声明
void print(struct
Student *);
void del(struct
Student *,int);
void insert(struct
Student *,int);
void combine(struct
Student *,struct
Student *,int,int);
void del2(struct
Student *,struct
Student*,int,int);
void del3(struct
Student*,int);
struct Student *heada,*headb;
heada=creat2();
//生成一个链表
L1=n;
headb=creat2();
//生成第二个链表
L2=n;
int choice;
printf("What do you want?\n1:print the LinkedList\n2:delete a member of the LinkedList a\n3:insert a member to the LinkedList a\n4:comine the two LinkedLists
and reform them according to 'num'\n5:delete the members of LinkedList a if that are same as those of LinkedList b\n6:delete the members of LinkedList a with the certain 'num'\n");
scanf("%d",&choice);
switch(choice)
{
case 1:print(heada);break;
//调用各函数
case 2:del(heada,L1);break;
case 3:insert(heada,L1);break;
case 4:combine(heada,headb,L1,L2);break;
case 5:del2(heada,headb,L1,L2);break;
case 6:del3(heada,L1);break;
}
return 0;
}