清华大学-数据结构(c语言版)单向链表代码

链表可以加深我们对指针、结构体的理解。

我发现了一个问题,书中的代码不完全是c语言的代码,因为c语言没有引用,所以我便对书中代码加以修改。

欢迎各位大佬指点。

话不多说,上代码:

/*
本章节疑问:为什么链表要使用结构体指针变量?
(1)指针节省内存主要体现在参数传递上,比如传递一个结构体指针变量和传递一个结构体变量,
结构体占用内存越大,传递指针变量越节省内存的,也就是可以减少不必要的数据复制。 
(2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等。
*/
/*------------------------线性表的单向单链表操作集-------------------------*/
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define OK 1                    //返回值
#define ERROR 0
#define VOERFLOW -1
typedef int Elemtype;           //数据类型
typedef int Status;             //返回值类型

void test1();                   //测试代码
void test2();
void test3();
void test4();

//单链表结构体
typedef struct LNode{
    Elemtype data;              //链表的数据域
    struct LNode *next;         //链表的指针域
}LNode,*LinkList;               //结构体变量名,结构体指针变量名

//查找链表中对应的元素
Status GetElem_L(LinkList L,int i,Elemtype *e){
    //L为带头结点的单链表的头指针
    //当第i各元素存在时,将其值赋给e并返回OK,否则则返回ERROR
    
    //初始化
    LinkList p;                
    int c=1;                    //计数器
    p=L->next;                  //p指向第一各结点

    //查找i是否存在
    while(p&&c<i){              //顺时针查找,直到p指向第i各元素或p为空
        p=p->next;
        ++c;
    }
    if(!p||c>i){                //第i各元素不存在
        return ERROR;
    }

    //存在则赋值
    *e=p->data;                  //将第i个结点的数据域的值赋给e
    return OK;
}

//往链表的指定位置插入一个元素
Status ListInsert_L(LinkList L,int i,Elemtype e){
    //在带头结点的单链线性表L中第i个位置之前插入元素e

    //初始化
    LinkList p,tem;
    int c=0;
    p=L;

    //查找到第i-1个结点
    while (p&&c<i-1){
        p=p->next;
        ++c;
    }

    //判断i是否存在
    if(!p||c>i-1){                //i小于1或者大于表长加1
        return ERROR;
    }

    //插入操作
    tem=(LinkList)malloc(sizeof(LNode));//申请新结点
    tem->data=e;                        
    tem->next=p->next;                  //有先后顺序,先后再前
    p->next=tem;

    return OK;
}

//删除链表中指定位置的元素
Status ListDele_L(LinkList L,int i,Elemtype *e){
    //在带头结点的单链表L中,删除第i个元素,并由e带出
    
    //初始化
    int c=0;
    LinkList q,p;
    p=L;

    //查找第i个元素,并且让p指向其前驱
    while(p->next&&c<i-1){
        p=p->next;
        ++c;
    }

    //判断后面是否还有元素和i是否存在
    if(!(p->next)||c>i-1){
        return ERROR;
    }

    //将要删除的元素赋给q,再释放q
    q=p->next;                          //无先后顺序
    p->next=q->next;
    free(q);                            //释放q,防止内存泄漏
    return OK;
}

//逆序输入链表元素
Status ListCreate_FL(LinkList L,int n){
    //逆序位输入n个元素的值,建立带表头结点的单链表L
    //定义一个中间变量p、q,p用于存储新输入结点的元素,q用于操作之后赋给L,再由L带出

    //初始化
    LinkList p;
    int i=0;        
    L->next=NULL;                       //使头节点的next为空,否则会出现下方逆序代码的q->next的地址不同

    //输入和逆序操作
    for(i=n;i>0;--i){
        p=(LinkList)malloc(sizeof(LNode));//输入
        scanf("%d",&(p->data));
        p->next=L->next;                //逆序,先后再前
        L->next=p;
    }
    return OK;
}

//顺序输入链表元素
Status ListCreate_L(LinkList L,int n){
    //顺序位输入n个元素的值,建立带表头结点的带单链表L
    //定义一个中间变量p、q,p用于存储新输入结点的元素,q用于操作之后赋给L,再由L带出
    //与逆序代码相似,变换了后面交换的代码

    //初始化
    LinkList p;
    int i;
    L->next=NULL;

    //输入并且按顺序插入
    for(i=n;i>0;--i){
        p=(LinkList)malloc(sizeof(LNode));//输入
        scanf("%d",&(p->data));
        p->next=NULL;                     //顺序插入
        L->next=p;
        L=L->next;                        //结点后移一位
    }
    return OK;
}

//将两个有序的链表合并成一个
Status ListMerge_L(LinkList La,LinkList Lb,LinkList Lc){
    //已知单链表La和Lb有序且按值非递见排序
    //归并La和Lb得到新单链线性表Lc,Lc的元素也按非递减排列

    //初始化
    LinkList pa,pb,pc;
    pa=La->next;
    pb=Lb->next;
    pc=Lc;

    //归并排序
    while(pa&&pb){
        if(pa->data<=pb->data){         //比较两个链表里面元素的大小
            pc->next=pa;                //把pa赋给pc
            pc=pc->next;                //pc指针往后移                      
            pa=pa->next;                //pa指针往后移
        }else{
            pc->next=pb;
            pc=pc->next;
            pb=pb->next;
        }
    }
    while(pa){                          //插入剩余段
        pc->next=pa;
        pc=pc->next;                         
        pa=pa->next;
    }  
    while(pb){                         
        pc->next=pb;
        pc=pc->next;                         
        pb=pb->next;
    }                
    free(Lb);                           //释放Lb的头节点
    free(La);                           //释放La的头节点
    return OK;
}

int main(void){
    test4();
    system("pause");                    //使运行结果在终端输出
    return 0;
}

void test1(){
    LinkList p;
    int e;
    p=(LinkList)malloc(sizeof(LNode));
    if(ListInsert_L(p,1,11))
    printf("OK\n");
    else printf("ERROR\n");
    if(GetElem_L(p,1,&e))
    printf("%d\n",e);
    else printf("ERROR\n");
    if(ListDele_L(p,1,&e))
    printf("%d\n",e);
}

void test2(){
    LinkList p;
    int i=0;
    p=(LinkList)malloc(sizeof(LNode));
    if(ListCreate_FL(p,3)){
        printf("OK\n");
    }
    for(i;i<3;++i){
        p=p->next;
        printf("%d  ",p->data);
    }
}

void test3(){
    LinkList p;                         
    p=(LinkList)malloc(sizeof(LNode));      //在传入前需要开辟空间   
    //使用前需要先用head记录头结点的位置,因为ListCreat_L函数操作之后指针会指向最后一个结点
    LinkList head=p;
    int i=0;    
    if(ListCreate_L(p,3)){
        printf("OK\n");
    }
    p=head;
    for(i=0;i<3;++i){
        p=p->next;
        printf("%d  ",p->data);
    }
}

void test4(){
    int i=0;
    LinkList p1;
    p1=(LinkList)malloc(sizeof(LNode));    
    if(ListCreate_FL(p1,3)){
        printf("OK\n");
    }
    LinkList p2;
    p2=(LinkList)malloc(sizeof(LNode));    
    if(ListCreate_FL(p2,3)){
        printf("OK\n");
    }
    LinkList p3;
    p3=(LinkList)malloc(sizeof(LNode)); 
    if(ListMerge_L(p1,p2,p3)){
       printf("OK\n"); 
    }
    for(i=0;i<6;i++){
        p3=p3->next;
        printf("%d  ",p3->data);
    }
}

使用vscode的方式在我第一个代码笔记中,这里我就不演示了。

接下来上运行结果:

测试代码1(插入。获取、删除操作):

 测试代码2(逆序输出测试):

测试代码3(顺序输出测试):

 

 测试代码4(合并代码测试):

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值