单链表的各项操作

数据结构单链表的各项操作

#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值