数据结构单链表的各项操作
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int data;
struct Node *next;
}LinkNode;
void CreateListF(LinkNode *&L,int a[],int n){//头插法建立单链表
LinkNode *s;
L=(LinkNode *)malloc(sizeof(LinkNode));//建立头结点
L->next=NULL;
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
s->next=L->next;
L->next=s;
}
}
void CreateListR(LinkNode *&L,int a[],int n){//尾插法建立单链表
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL;//建立头结点
r=L;//用新的指针指向链表,是防止L的指向指向表尾,之后再去操作单链表不方便
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
r->next=s;
r=s;
}
r->next=NULL;
}
void CreateListR1(LinkNode *L,int a[],int n){//不使用引用,L只是个形参,调用函数一结束,L定义的线性表空间就会释放
LinkNode *s;
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL;
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
L->next=s;
L=s;
}
L->next=NULL;
}
void CreateListR1(LinkNode *&L,int a[],int n){
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode));
L->next=NULL;
for(int i=0;i<n;i++){
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=a[i];
L->next=s;
L=s;
}
L->next=NULL;
}//这样写,下面的L的地址会指向链表的末尾,后面的输出函数会从末尾开始输出数据
void DisplayList(LinkNode *L){//不用引用是因为,会改变L的只想,使其不再指向头结点,不方便后面的操作
L=L->next;//从第二个节点开始,也就是除了头结点
while(L!=NULL){
printf("%d ",L->data);
L=L->next;
}
printf("\n");
}
void DestroyList(LinkNode *&L){
LinkNode *pre=L,*p=L->next;
while(p!=NULL){
free(pre);
pre=p;
p=pre->next;
}
free(p);
printf("销毁成功\n");
}
void ListEmpty(LinkNode *L){
if(L->next==NULL)
printf("该链表为空\n");
else
printf("该链表不为空\n");
}
int ListLength(LinkNode *L){//求链表中有数据的节点个数,不包括头结点L,只是s节点的个数。要是加上头结点,应该是返回n+1
int n=0;
while(L->next!=NULL){
n++;
L=L->next;
}
return n;
}
void GetElem(LinkNode *L,int i){//输出第i个节点的值
int t=i;
if(i<0){
printf("error\n");
return;
}
else{
while(i--&&L!=NULL){
L=L->next;
}
if(L==NULL)
printf("error\n");
else{
printf("第%d个数的值为:%d\n",t,L->data);
}
}
}
void LocateElem(LinkNode *L,int e){
int i=0;//这里的i实际上是加上头节点的序号,但因为尾节点没有记录上,实际上还是带数据的节点
while(L->next!=NULL){
if(L->data==e)
printf("数据值是%d的是第%d个节点\n",e,i);
i++;
L=L->next;
}
if(L->data!=e)
printf("没有找到该数值\n");
else
printf("数据值是%d的是第%d个节点\n",e,i);
}
void LocateElem1(LinkNode *L,int e){
int i=1,t=0;
LinkNode *p=L->next;
while(p!=NULL){
if(p->data==e){
printf("数据值是%d的是第%d个节点\n",e,i);
t=1;
}
i++;
p=p->next;
}
if(p==NULL&&t==0)
printf("没有找到该值\n");
}
void LocateElem2(LinkNode *L,int e){
int i=0;//这里的i实际上是加上头节点的序号,但因为尾节点没有记录上,实际上还是带数据的节点
while(L->next!=NULL&&L->data!=e){
i++;
L=L->next;
}
if(L->data!=e)
printf("没有找到该数值\n");
else
printf("数据值是%d的是第%d个节点\n",e,i);
}
void LocateElem3(LinkNode *L,int e){//这是最方便的方法去解决查找值的问题,让L已经开始指向第二个节点,让i=1;
int i=1;
LinkNode *p=L->next;//i=1,是因为L一开始就指向了第二个节点(除了头节点),这里的i代表是有数据的节点的序号
while(p!=NULL&&p->data!=e){
i++;
p=p->next;
}
if(p==NULL)
printf("没有找到该数值\n");
else
printf("数据值是%d的是第%d个节点\n",e,i);
}
void ListInsert(LinkNode *&L,int i,int e){
LinkNode *r=L,*s;//这里的指向链表的指针变量r是形参,他是代替了L进行操作,为了不改变L的指向第一个节点,形参释放,是释放空间,但是对L指向的链表的操作会保存起来
if(i<=0)
{
printf("error\n");
return;
}
else{
while(i--&&r->next!=NULL){//这里的i执行I次指向链表末尾的时候,i=0;但判断的时候,i=i-1;会变成-1;i长度小于等于带数据的节点数,IDE值一定会减小到-1;大于-1的都是查询的值超过链表的长度。
r=r->next;
}
}
//if(r==NULL)超过链表的长度并没有报警
if(i>-1)
printf("error\n");
else{
s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=e;
s->next=r->next;
r->next=s;
}
}
void ListDelete(LinkNode *&L,int i){
LinkNode *r=L;
i=i-1;//要删除某个节点,要指向该节点的前驱结点,而不是要删除的节点
if(i<0){
printf("error\n");
return;
}
else{
while(i--&&r->next!=NULL)
r=r->next;
}
if(r==NULL){
printf("error\n");
}
else{
r->next=r->next->next;//指向要删除节点的前驱结点
}
}
void AlterList(LinkNode *&L,int i,int e){
LinkNode *r=L;
if(i<=0){
printf("error\n");
return;
}
else {
while(i--&&r->next!=NULL){
r=r->next;
}
}
if(r==NULL)
printf("error");
else{
r->data=e;
}
}
void ListDeleteX(LinkNode *L){//删除单链表中最小元素
int x=L->next->data;
LinkNode *p,*q;
while(L->next!=NULL){//指向最后的时候,结束
if(L->next->data<x){
p=L;//p记录的是较小值的前驱结点
x=L->next->data;
}
L=L->next;
}
q=p->next;//q指向最小值
p->next=p->next->next;//单链表中删除最小值
free(q);//释放最小值的空间
}
void ListDelete2(LinkNode *&L,int x){//删除值为x的节点,并释放空间,利用头插法,遍历原来的链表,等于x的节点舍弃,不等于x的结点插入到新的链表之中
LinkNode *p=L->next,*q,*r=L;
L->next=NULL;
while(p){
if(p->data!=x){
r->next=p;
r=p;
p=p->next;
}
else{
q=p;
p=p->next;
free(q);
}
}
r->next=NULL;
}
void ListDelete3(LinkNode *&L,int x){//利用递归思想
LinkNode *p;
if(L==NULL)//递归的结束条件
return;
if(L->data==x){//递归体
p=L;
L=L->next;
free(p);
ListDelete3(L,x);
}
else
ListDelete3(L->next,x);
}
void ReverseList(LinkNode *&L){
LinkNode *p=L->next,*q;
L->next=NULL;//取下头结点
while(p){
q=p->next;
p->next=L->next;
L->next=p;
p=q;
}
}
void ReverseList2(LinkNode *&L){//用三个指针逆置单链表
LinkNode *p=L->next,*q=p->next,*pre;//pre,p,q分别指向相邻的三个结点,
p->next=NULL;//处理第一个结点,使其指针域指向NULL
while(q){
pre=p;
p=q;
q=q->next;//每次移动三个指针
p->next=pre;//让p的指针指向它的前驱结点
}
L->next=p;//处理最后一个节点,使头结点指向他
}
void ListSort(LinkNode *&L){//排序。让单链表按照递增的顺序排列
LinkNode *pre=L->next,*p=L->next->next,*r;//采用擦汗如排序的思想
pre->next=NULL;
while(p){
r=p->next;
pre=L;
while(pre->next!=NULL){
if(p->data<pre->next->data){
p->next=pre->next;
pre->next=p;
p=r;
break;
}
pre=pre->next;
}
}
}
void ListSort1(LinkNode *&L){//排序。让单链表按照递增的顺序排列
LinkNode *pre,*p=L->next,*r=p->next;
p->next=NULL;
p=r;
while(p){
r=p->next;
pre=L;
while(pre->next!=NULL&&pre->next->data<p->data)
pre=pre->next;
p->next=pre->next;
pre->next=p;
p=r;
}
}
int main(){
LinkNode *L;
int n,a[15],i,e,number;
printf("请输入链表长度和链表数据:");
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
printf("<-单链表的操作->\n");
printf("1:创建单链表\n");
printf("2:销毁单链表\n");
printf("3:输出单链表\n");
printf("4:输出单链表的长度\n");
printf("5:判断单链表是否为空\n");
printf("6:单链表插入数据\n");
printf("7:删除单链表的数据\n");
printf("8:修改单链表的值\n");
printf("9:按照序号查询单链表的值\n");
printf("10:按照值查询单链表的值\n");
printf("11:删除单链表中最小值\n");
printf("12:删除单链表中所有值为x的元素\n");
printf("13:逆置单链表中的结点\n");
printf("14:将单链表按递增顺序排列\n");
while(1){
printf("请输入需要执行的操作序号:");
scanf("%d",&number);
switch(number){
case 1:CreateListR(L,a,n);
printf("创建链表成功\n");
break;
case 2:DestroyList(L);
break;
case 3:DisplayList(L);
break;
case 4:printf("该单链表的长度是:%d\n",ListLength(L));
break;
case 5:ListEmpty(L);
break;
case 6:printf("请输入要插入的序号和要插入的值:");
scanf("%d %d",&i,&e);
ListInsert(L,i,e);
break;
case 7:printf("请输入需要删除数据的序号是:");
scanf("%d",&i);
ListDelete(L,i);
break;
case 8:printf("请输入需要修改数据的序号和数据:");
scanf("%d %d",&i,&e);
AlterList(L,i,e);
break;
case 9:printf("请输入需要查找数据的序号是:");
scanf("%d",&i);
GetElem(L,i);
break;
case 10: printf("请输入需要查找的值是:");
scanf("%d",&e);
LocateElem1(L,e);
case 11:ListDeleteX(L);
printf("删除成功\n");
break;
case 12:printf("请输入要删除的值");
scanf("%d",&number);
ListDelete3(L,number);
break;
case 13:ReverseList2(L);
break;
case 14:ListSort(L);
break;
default:printf("请输入正确的操作序号");
}
}
return 0;
}