编写一个完整的程序,实现单链表的建立、插入、删除、输出等基本操作。
(1)建立一个带头结点的单链表。
(2)计算单链表的长度,然后输出单链表。
(3)查找值为x的直接前驱结点q。
(4)删除值为x的结点。
(5)把单向链表中元素逆置(不允许申请新的结点空间)。
(6)已知单链表中元素递增有序,请写出一个高效的算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度(注意:mink和maxk是给定的两个参变量,他们的值可以和表中的元素相同,也可以不同)。
(7)同(6)的条件,试写一高效的算法,删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同),同时释放被删结点空间,并分析你的算法时间复杂度。
(8)利用(1)建立的链表,实现将其分解成两个链表,其中一个全部为奇数,另一个全部为偶数(尽量利用已知的存储空间)。
(9)在主函数中设计一个简单的菜单,分别测试上述算法。
//因为没有要求输入的链表数据的数量,所以我用-1表示输入结束。
//测试数据 1 2 3 4 5 6 -1
//测试删除相同元素的数据 2 2 3 3 4 4 5 5
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
node *next;
};
node *h,*h1,*h2;
void Creatlist()//创建链表
{
node *s,*e;
h=(node *)malloc(sizeof(node));
s=(node *)malloc(sizeof(node));
h->next=s;
printf("请输入单链表数据: ");
scanf("%d",&s->data);
e=h;
while(s->data!=-1)//用-1表示链表输入终止
{
e=s;
s=(node *)malloc(sizeof(node));
scanf("%d",&s->data);
e->next=s;
}
e->next=NULL;
return ;
}
void Printlist(node *h)//输出链表
{
int count;
node *s;
s=h;
count=0;
while(s->next!=NULL)//先遍历一遍,用count记录链表的长度。
{
count++;
s=s->next;
}
printf("单链表长度: %d\n",count);
if(count==0)
{
printf("链表为空!\n");
return ;
}
printf("单链表数据: ");
s=h;
while(s->next!=NULL)
{
s=s->next;
printf("%d ",s->data);
}
printf("\n");
return ;
}
void Findlist()//查找值为x的前驱结点
{
int x;
node *s,*e;
printf("请输入待查找的数值: ");
scanf("%d",&x);
s=h->next;
if(s->data==x)
{
printf("%d没有前驱结点!\n",x);//x为第一个结点
return ;
}
e=s->next;
while(e->data!=x&&e->next!=NULL)
{
s=e;
e=s->next;
}
if(e->data!=x)
{
printf("单链表中不存在值为%d的结点!\n",x);//链表中没有x
return ;
}
printf("%d的前驱结点为: %d\n",x,s->data);
return ;
}
void Deletlist()//删除值为x的结点,实验中没有要求,我写的时候是按链表中只有一个值为x的结点。
{
int x;
node *s,*e;
printf("请输入需要删除的数值: ");
scanf("%d",&x);
s=h;
e=s->next;
while(e->data!=x&&e->next!=NULL)
{
s=e;
e=s->next;
}
if(e->data!=x)
{
printf("单链表中不存在值为%d的结点!\n",x);//链表中没有值为x的结点
return ;
}
s->next=e->next;
free(e);
return ;
}
void Inverlist()//逆置链表,将连接链表的指针方向倒转,不需要申请新的空间。
{
node *s,*e,*r;
s=h->next;
e=s->next;
if(e==NULL)
{
h->next=s;
return ;
}
s->next=NULL;
r=e->next;
while(e!=NULL)
{
e->next=s;
s=e;
e=r;
if(e==NULL)
break;
r=e->next;
}
h->next=s;
return ;
}
void Delexylist()//删除链表中x和y之间的数字,而且要求释放内存。既然要求释放内存,那就只能遍历,我没想到什么更高效的算法,因为链表是有序的,我释放到值为y结束。
{
int x,y;
node *s,*e,*r;
printf("请输入需要删除的区间 ");
scanf("%d %d",&x,&y);
r=h;
s=h->next;
while(s->data<=y&&s->next!=NULL)
{
e=s->next;
if(s->data>=x)
{
free(s);
r->next=e;
}
else
r=s;
s=e;
}
return ;
}
void DeleSamelist()//删除相同元素的结点同时释放内存空间。同样需要遍历,没有想到特别高效的算法。
{
int temp;
node *s,*e,*r;
r=h;
s=h->next;
if(s==NULL)
return ;
temp=-1;
while(s!=NULL)
{
e=s->next;
if(s->data==temp)
{
free(s);
r->next=e;
}
else
{
temp=s->data;
r=s;
}
s=e;
}
return ;
}
void Cutlist()//分拆链表。
{
node *s,*s1,*e1,*s2,*e2;
h1=(node *)malloc(sizeof(node));
s1=(node *)malloc(sizeof(node));
h2=(node *)malloc(sizeof(node));
s2=(node *)malloc(sizeof(node));
e1=h1;
e1->next=NULL;
e2=h2;
e2->next=NULL;
s=h->next;
while(s!=NULL)
{
if(s->data%2!=0)
{
s1->data=s->data;
e1->next=s1;
e1=s1;
e1->next=NULL;
s1=(node *)malloc(sizeof(node));
}
else
{
s2->data=s->data;
e2->next=s2;
e2=s2;
e2->next=NULL;
s2=(node *)malloc(sizeof(node));
}
s=s->next;//第一次写的时候没有加上这一句,电脑直接就卡死了。。。。
}
Printlist(h1);
Printlist(h2);
return ;
}
int Opra()
{
int T;
printf("*****************目录******************\n");
printf("创建一个单链表: 1\n");
printf("计算单链表长度并输出单链表: 2\n");
printf("查找值为x的前驱结点: 3\n");
printf("删除值为x的结点: 4\n");
printf("把单链表中的元素逆置: 5\n");
printf("删除单链表中值在x和y之间的元素: 6\n");
printf("删除链表中值相同的元素: 7\n");
printf("将链表分成两部分: 8\n");
printf("操作结束: 0\n");
printf("输入操作代号: ");
scanf("%d",&T);
switch(T)
{
case 1:Creatlist();break;
case 2:Printlist(h);break;
case 3:Findlist(); break;
case 4:Deletlist();break;
case 5:Inverlist();break;
case 6:Delexylist();break;
case 7:DeleSamelist();break;
case 8:Cutlist();break;
case 0:return 0;
default :printf("输入错误,请重新输入!\n");break;
}
return 1;
}
int main()
{
int flag=1;
while(1)
{
flag=Opra();
if(!flag)//用flag控制是否跳出循环。
break;
printf("\n\n");
}
printf("谢谢使用!\n");
return 0;
}