码迷,mamicode.com
首页 > 编程语言 > 详细

C语言简单实现线性表的链式存储结构(单链结构)

时间:2020-07-24 15:23:15      阅读:78      评论:0      收藏:0      [点我收藏+]

标签:信息   linked   释放   元素   验证   sel   就是   etl   intel   

为了方面使用,先定义头文件ElemType

#include "stdio.h"
typedef double ElemType;

//操作成功
#define OK 1
//操作错误
#define ERROR 0
//操作异常
#define OVERFLOW -2
//定义元素类型,int可使用基本数据类型和用户自定义数据类型替换,根据使用场景选择
typedef int Status ;

double absForDouble(double a);

/**
 * 求绝对值
 * @param a
 * @return 返回a的绝对值
 */
double absForDouble(double a) {
    if (a < 0)return -a;
    return a;
}

/**
 * 实现两个ElemType类型变量的匹配
 * @param e1 ElemType类型变量e1
 * @param e2 ElemType类型变量e2
 * @return 匹配结果,1表示匹配,0表示不匹配
 */
int match(ElemType e1, ElemType e2){
    if(absForDouble(e1-e2)<1e-6)
        return 1;
        return 0;
}

/**
 * 打印数据元素
 */
printElem(ElemType e){
    printf("Current element‘s data is %lf!\n",e);
}

 

注发现上面代码框的代码和下面代码框的代码均包含了语句#include<stdio.h>

会不会造成不好的结果呢?

详情请点击链接 C语言中包含一个头文件多次的后果以及解决方案

因为stdio.h使用了

#ifndef

#endif

故不会产生不良影响

 

实现单链表的定义

#include "ElemType.h"
#include "stdlib.h"
#include<stdio.h>

/**
 * 线性表的链式存储结构
 * 什么是线性表的链式存储结构?
 * 使用一组任意的存储单元存储线性表的数据元素,这些存储单元可以是连续的,也可以是不连续的,而为了表现线性表中各元素的直接后继关系,在数据元素的基础上
 * 额外的使用指针来存储当前数据元素的直接后继的位置信息,这样的包含了数据元素的数据和数据元素的直接后继位置信息的数据结构称之为结点,而由n个结点链接
 * 成一个链表,即为线性表的链式存储结构。一般的,把线性表的链式存储结构简称为单链表或者线性链表,而结点存储数据元素本身信息的部分称之为数据域,而存储
 * 数据元素的直接后继的位置信息的部分称之为指针域。换而言之,在单链表中用以存储线性表的逻辑关系的是指针域
 */

/**
 * 单链表的定义
 * 关于LNode* 和LinkedList的区别:一般的,LinkedList表示的是指向单链表的头结点(在首元结点前预设的额外的结点,其数据域不存储任何信息)的指针,而LNode*则是指指向单链表的结点的指针。
 * 头指针:指向链表中第一个结点指针(若不预设头结点,则指向首元结点,否则指向头结点)
 * 首元结点:存储线性表第一个数据元素的结点
 * 为何预设头结点?
 * 1、便于首元结点的处理,首元结点作为头结点的直接后继
 * 2、便于头指针对空表和非空表作同一处理,无论线性表是否为空表,头指针都是指向头结点的非空指针
 */
typedef struct LNode {
    ElemType data;
    struct LNode *next;
} LNode, *LinkedList;

 

单链表基本操作的简单实现

/**
 * 单链表基本操作的实现
 */

/**
 * 初始化
 * 算法描述:1、新建头结点,使头指针L指向头结点
 * 2、置头结点的指针域为空(NULL)
 * @param L 指向单链表头指针的指针(实现动态内存的传递)
 * @return 操作结果状态码
 */
Status initLinkedList(LinkedList *L) {
    //新建头结点,使头指针L指向头结点
    *L = (LNode *) malloc(sizeof(LNode));
    //新建结点失败
    if (!L) return OVERFLOW;
    //置头结点的指针域为空(NULL)
    (*L)->next = NULL;
    (*L)->data = 0;
    return OK;
}

/**
 * 销毁单链表
 * 算法描述:
 * 1、判断指向头指针的指针L指向的指针是否指向NULL
 * 2、若L指向NULL,则单链表已被销毁,或者单链表为初始化,无法销毁,返回ERROR
 * 3、若L不指向NULL,定义指向当前结点的指针p并使其指向头结点
 * 4、定义临时指针t指向NULL
 * 5、使用循环销毁结点,首先使指针t指向指向当前结点的指针p指向的结点的直接后继,销毁指针p指向的结点,使p指向指针t指向的结点,若p!=NULL,再次循环
 * 6、置指针L,p,t指向NULL
 * 7、返回OK
 * @param L 指向单链表头结点的指针L
 * @return 操作结果状态码
 */
Status destroyLinkedList(LinkedList *L) {
    //判断指向头指针的指针L指向的指针是否指向NULL
    //L指向NULL,则单链表已被销毁,或者单链表为初始化,无法销毁,返回ERROR
    if (!(*L)) {
        return ERROR;
    }
    //若L不指向NULL,定义指向当前结点的指针p并使其指向头结点
    LNode *p = *L;
    //定义临时指针t指向NULL
    LNode *t = NULL;
    while (p) {
        //使指针t指向指向当前结点的指针p指向的结点的直接后继
        t = p->next;
        //销毁指针p指向的结点
        free(p);
        //使p指向指针t指向的结点
        p = t;
    }
    //置指针L,p,t指向NULL
    t = NULL;
    p = NULL;
    L = NULL;
    ////返回OK
    return OK;
}

/**
 * 清空单链表
 * 算法描述:
 * 1、判断指向头指针的指针L指向的指针是否指向NULL
 * 2、若L指向NULL,则单链表已被销毁,或者单链表为初始化,无法清空,返回ERROR
 * 3、若L不指向NULL,定义指向当前结点的指针p并使其指向首元结点
 * 4、定义临时指针t指向NULL
 * 5、使用循环销毁结点,首先使指针t指向指向当前结点的指针p指向的结点的直接后继,销毁指针p指向的结点,使p指向指针t指向的结点,若p!=NULL,再次循环
 * 6、置指针p,t指向NULL
 * 7、置头结点的指针域为NULL
 * 8、返回OK
 * @param L 指向单链表的头指针的指针
 * @return 操作结果状态码
 */
Status clearLinkedList(LinkedList *L) {
    //判断指向头指针的指针L指向的指针是否指向NULL
    //L指向NULL,则单链表已被销毁,或者单链表为初始化,无法清空,返回ERROR
    if (!(*L)) {
        return ERROR;
    }
    //若L不指向NULL,定义指向当前结点的指针p并使其指向头结点
    LNode *p = (*L)->next;
    //定义临时指针t指向NULL
    LNode *t = NULL;
    while (p) {
        //使指针t指向指向当前结点的指针p指向的结点的直接后继
        t = p->next;
        //销毁指针p指向的结点
        free(p);
        //使p指向指针t指向的结点
        p = t;
    }
    //置头结点的指针域为NULL
    (*L)->next = NULL;
    //置指针p,t指向NULL
    t = NULL;
    p = NULL;
    ////返回OK
    return OK;
}

/**
 * 判断单链表是否为空表
 * 算法描述:
 * 1、判断指针L的合法性(是否等于NULL),若等于NULL,置res指向的存储单元的值为0,返回ERROR
 * 1、只需更加头指针L的指针域即可判断,若L->next=NULL,则单链表是空表,若L->next!=NULL,则单链表不是空表,综上返回L指针域值的取反值即可
 * @param L 指向单链表的头指针L
 * @param res 指向保存单链表是否为空表的信息的存储单元的指针res
 * @return 操作结果状态码
 */
Status isEmpty(LinkedList L, int *res) {
    if (!L) {
        *res = 0;
        return ERROR;
    }
    //只需更加头指针L的指针域即可判断,若L->next=NULL,则单链表是空表,若L->next!=NULL,则单链表不是空表,综上返回L指针域值的取反值即可
    *res = !L->next;
    return OK;
}

/**
 * 获取单链表的长度
 * 算法描述:
 * 1、判断头指针L是是否等于NULL,若等于NULL,表示单链表未初始化或已经被销毁,置指针len指向的存储单元的值为-1,返回ERROR
 * 2、定义指向当前结点的指针p并使其指向单链表的头结点
 * 3、定义计数器j记录指针p由头结点移动至尾结点需要移动的次数,即单链表的长度,置j初始值为零
 * 4、循环移动指针p的位置并使计数器自增,直至p=NULL(表示指针p指向尾结点的后继)
 * 5、置指针len指向存储单元的值为变量j的值
 * 6、使指针p指向NULL,返回OK
 * @param L 指向单链表的头结点的头指针L
 * @param len 指向用以保存单链表长度的指针len
 * @return
 */
Status getLength(LinkedList L, int *len) {
    //判断头指针L是是否等于NULL,若等于NULL,表示单链表未初始化或已经被销毁,置指针len指向的存储单元的值为-1,返回ERROR
    if (!L) {
        *len = -1;
        return ERROR;
    }
    //定义指向当前结点的指针p并使其指向单链表的头结点
    LNode *p = L->next;
    //定义计数器j记录指针p由头结点移动至尾结点需要移动的次数,即单链表的长度,置j初始值为零
    int j = 0;
    //循环移动指针p的位置并使计数器自增,直至p=NULL(表示指针p指向尾结点的后继)
    while (p) {
        p = p->next;
        ++j;
    }
    //置指针len指向存储单元的值为变量j的值
    *len = j;
    //返回OK
    p = NULL;
    return OK;

}

/**
 * 取值,取单链表的第i个元素(i>0且i<n+1)
 * 算法描述:使指向当前结点的指针p指向首元结点,用计数器j计数,j初始值为1,从首元结点开始依次访问单链表的结点,直至指向当前结点的指针p的指针域为NULL
 * 或者计数器为i(即访问到了序号为p的结点),否则不断进行如下循环:
 * 1、p指向下一结点
 * 2、J自增
 * 当上述循环结束时,若计数器小于i,返回ERROR
 * 否则,使用参数e保存序号为i的结点的数据域并返回OK表示取值成功
 * @param L 指向头指针的指针
 * @param i 欲访问元素的结点序号
 * @param e 指向保存序号为i的结点的数据域的数据元素的指针
 * @return 操作结果状态码
 */
Status getElem(LinkedList L, int i, ElemType *e) {
    //使指向当前结点的指针p指向首元结点
    LNode *p = L->next;
    //用计数器j计数,j初始值为1
    int j = 1;
    //从首元结点开始依次访问单链表的结点,直至指向当前结点的指针p的指针域为NULL或者计数器为i(即访问到了序号为p的结点)
    while (j < i && p) {
        p = p->next;
        ++j;
    }
    //若!p为真,说明p当前指向NULL,即指向最后一个结点指针域指向的结点即第n+1个结点,说明i>n,i非法,返回ERROR
    //若j > i,由于j初始值为1,j>0,故得i<=0,i非法,返回ERROR
    if (!p || j > i) return ERROR;
    //否则,使用参数e保存序号为i的结点的数据域并返回OK表示取值成功
    *e = p->data;
    p = NULL;
    //返回OK
    return OK;
}

/**
 *  定位单链表中与e匹配的数据元素的位置
 * 算法描述:
 * 1、定义指向当前结点的指针p,令其指向首元结点
 * 2、遍历单链表直至存在找到数据欲和e匹配的结点
 * 3、若p==NULL,条件表达式p为假,退出循环,说明查找到了最后一个结点后的结点,计数器等于n+1(n为单链表的长度),查找失败,将-1赋值给指针i指向的内存,返回ERROR
 * 4、若查找成功,此时计数器恰好等于该节点在单链表的序号,将计数器的值赋值给指针i指向的内存,返回OK
 * @param L 指向单链表头指针的指针
 * @param i 指针传参,用以保存查找结果
 * @param e 欲查找的数据元素
 * @return 操作结果状态码
 */
Status indexOf(LinkedList L, int *i, ElemType e) {
    //定义指向当前结点的指针p,令其指向首元结点
    LNode *p = L->next;
    //定义计数器j = 1
    int j = 1;
    //遍历单链表直至存在找到数据欲和e匹配的结点
    //当p==NULL时条件表达式p为假,退出循环,说明查找到了最后一个结点后的结点,计数器等于n+1(n为单链表的长度),查找失败
    //当absForDouble(p->data-e)<1e-6(ElemType是浮点数,不能使用等于符号),说明查找成功,此时计数器恰好等于该节点在单链表的序号
    /*printf("%lf %lf\n",p->data,e);
    printf("%d\n",p);
    printf("%d\n",p&&(p->data-e)>1e-6);*/
    while (p && absForDouble(p->data - e) > 1e-6) {
        p = p->next;
        ++j;
    }
    //若j > n,说明没有找到匹配元素,置i值为-1,返回ERROR,表示查找失败
    if (!p) {
        *i = -1;
        return ERROR;
    }
    //否则j <= n,查找到匹配元素, 置i值为计数器j的值
    *i = j;
    //返回OK,表示查找成功
    p = NULL;
    return OK;
}

/**
 * 查找单链表L中数据域与给定数据e匹配的结点,并返回该结点的地址
 * 算法描述:
 * 1、定义指向当前结点的指针,使其指向单链表L的首元结点
 * 2、从首元结点开始遍历单链表L,依次用每个结点的数据域匹配给定数据e,直至指向当前结点的指针p指向NULL或匹配成功
 * 3、返回指向当前结点的指针p
 * @param L 单链表的头指针
 * @param e 欲查找的数据域
 * @return p 返回查找与给定数据域匹配的结点的地址
 */
LNode *locateElem(LinkedList L, ElemType e) {
    //定义指向当前结点的指针,使其指向单链表L的首元结点
    LNode *p = L->next;
    //从首元结点开始遍历单链表L,依次用每个结点的数据域匹配给定数据e,直至指向当前结点的指针p指向NULL或匹配成功
    while (p && absForDouble(p->data - e) > 1e-6) {
        p = p->next;
    }
    //若p指向NULL说明查找失败
    //否则查找成功
    //返回指向当前结点的指针p
    return p;
}

/**
 * 获取前趋结点
 * 获取单链表上数据域等于curE的第一个结点的前趋结点,若该结点无前趋结点,置priorNode指向的内存单元的值为NULL
 * 算法描述:
 * 1、判断头指针L是否合法,若不合法,置priorNode指向的内存单元的值为NULL,返回ERROR
 * 2、定义指针curNode指向数据域等于curE的第一个结点的指针,使用locateElem()函数
 * 3、判断curNode是否等于L->next,若是,curNode为首元结点,无前趋,置priorNode指向的内存单元的值为NULL,返回ERROR
 * 4、定义指向当前结点的指针p并指向单链表的头结点
 * 5、循环移动指针p直至p->next=curNode
 * 6、指针p指向的结点为curNode的前趋,把指针p的值赋值给priorNode指向的内存单元
 * 7、置指针curNode,p为NULL,返回OK
 * @param L 指向单链表头结点的头指针L
 * @param curE 当前结点数据域
 * @param priorNode 指向数据域等于curE的上一个结点的指针的指针priorNode
 * @return 操作结果状态码
 */
Status priorElem(LinkedList L, ElemType curE, LNode **priorNode) {
    //判断头指针L是否合法,若不合法,置priorNode指向的内存单元的值为NULL,返回ERROR
    if (!L) {
        *priorNode = NULL;
        return ERROR;
    }
    //定义指针curNode指向数据域等于curE的第一个结点的指针,使用locateElem()函数
    LNode *curNode = locateElem(L, curE);
    //判断curNode是否等于L->next,若是,curNode为首元结点,无前趋,置priorNode指向的内存单元的值为NULL,返回ERROR
    if (curNode == L->next) {
        *priorNode = NULL;
        return ERROR;
    }
    //定义指向当前结点的指针p并指向单链表的头结点
    LNode *p = L;
    //循环移动指针p直至p->next=curNode
    while (p->next != curNode) {
        p = p->next;
    }
    //指针p指向的结点为curNode的前趋,把指针p的值赋值给priorNode指向的内存单元
    *priorNode = p;
    //置指针curNode,p为NULL,返回ERROR
    curNode = NULL;
    p = NULL;
    return OK;
}

/**
 * 获取后继结点
 * 获取数据域为curE的结点的后继结点,若当前结点无后继结点,置nextNode指向的内存单元值为NULL,返回ERROR
 * 算法描述:
 * 1、判断头指针L是否合法,若不合法,置nextNode指向的内存单元的值为NULL,返回ERROR
 * 2、定义指向数据域为curE的结点的指针curNode(使用locateElem()函数)
 * 3、判断curNode->next是否为NULL,若为NULL,则curNode指向的结点为尾结点,无后继,置nextNode指向的内存单元为NULL,返回ERROR
 * 4、令指针nextNode指向的指针指向curNode指针域指向的结点(即把curNode->next的值赋值给指针nextNode指向的内存单元)
 * 5、置指针curNode为NULL,返回OK
 * @param L
 * @param curE
 * @param nexrNode
 * @return
 */
Status nextElem(LinkedList L, ElemType curE, LNode **nexrNode) {
    //判断头指针L是否合法,若不合法,置nextNode指向的内存单元的值为NULL,返回ERROR
    if (!L) {
        *nexrNode = NULL;
        return ERROR;
    }
    //定义指向数据域为curE的结点的指针curNode(使用locateElem()函数)
    LNode *curNode = locateElem(L, curE);
    //判断curNode->next是否为NULL,若为NULL,则curNode指向的结点为尾结点,无后继,置nextNode指向的内存单元为NULL,返回ERROR
    if (curNode->next == NULL) {
        *nexrNode = NULL;
        return ERROR;
    }
    //令指针nextNode指向的指针指向curNode指针域指向的结点(即把curNode->next的值赋值给指针nextNode指向的内存单元)
    *nexrNode = curNode->next;
    //置指针curNode为NULL,返回OK
    curNode = NULL;
    return OK;
}

/**
 * 插入结点到单链表
 * 算法描述:将数据域为e的结点插入到单链表的位置i上,即插入到第i-1个结点和第i-1个结点之间(i>0且i<n+2,n是单链表的当前长度),具体操作如下:
 * 1、查找第i-1个结点并使用指向当前结点的指针p指向该结点
 * 2、生成一个新的结点s
 * 3、置新结点s的数据域为e
 * 4、使s的指针域指向结点第i个结点
 * 5、使p指向的结点的指针域指针新结点s
 * 注意4、5两步的次序,必须通过第i-1个结点来访问第i个结点,因此必须先让新结点指向第i个结点,再让第i个结点指向新结点,否则无法访问第i个结点
 * @param L 指向头指针的指针
 * @param i 欲插入的位置
 * @param e 插入的结点的数据域
 * @return 操作结果状态码
 */
Status insertLNode(LinkedList *L, int i, ElemType e) {
    //使当前结点指向头结点
    LNode *p = (*L);
    //定义计数器j
    int j = 0;
    //查找第i-1个结点并使用指向当前结点的指针p指向该结点,若j >= i-1或者当前结点的指针为NULL循环终止
    while (j < i - 1 && p) {
        p = p->next;
        ++j;
    }
    //如果i > n+1 或者 i < 1,i非法,返回ERRPR
    if (!p || j > i - 1)return ERROR;
    //生成一个新的结点s
    LNode *s = (LNode *) malloc(sizeof(LNode));
    //置新结点s的数据域为e
    s->data = e;
    //使s的指针域指向结点第i个结点
    s->next = p->next;
    //使p指向的结点的指针域指针新结点s
    p->next = s;
    s = NULL;
    p = NULL;
    return OK;
}

/**
 * 删除单链表L上序号为i的结点,即删除单链表中序号为i-1和i+1之间的结点
 * 算法描述:
 * 1、定义指向当前结点的指针p,使其指向单链表的头结点
 * 2、定义计数器j = 0
 * 3、查找并使当前指向当前结点的指针序号为i-1的结点,修改计数器j的值,若i>n或i<1,返回ERROR,表示删除失败
 * 4、定义指针变量t(temp,临时指针变量)指向当前结点的下一结点(即序号为i的结点,亦即待删除的结点)
 * 5、使指向当前结点(序号为i-1的结点)的指针p指向的结点的指针域指向指针t的指针域指向的结点(序号为i+1的结点)
 * 6、释放指针变量t指向的结点所占用的内存
 * 7、使指针p、t指向NULL;
 * 8、返回OK,表示删除成功
 * @param L
 * @param i
 * @return
 */
Status deleteNode(LinkedList *L, int i) {
    //定义指向当前结点的指针p,使其指向单链表的头结点
    LNode *p = *L;
    //定义计数器j = 0
    int j = 0;
    //查找并使当前指向当前结点的指针序号为i-1的结点,修改计数器j的值,若i>n或i<1,返回ERROR,表示删除失败
    //
    while (p->next && j < i - 1) {
        p = p->next;
        ++j;
    }
    //p->next = NULL 表示序号为i-1的结点为最后一个结点,即序号i的结点是第n+1个结点,显然该结点不存在 > n,i值不合法,返回ERROR
    //j > i -1表示 i < 1,i值不合法,返回ERROR
    if (!(p->next) || j > i - 1) {
        return ERROR;
    }
    //定义指针变量t(temp,临时指针变量)指向当前结点的下一结点(即序号为i的结点,亦即待删除的结点)
    LNode *t = p->next;
    //使指向当前结点(序号为i-1的结点)的指针p指向的结点的指针域指向指针t的指针域指向的结点(序号为i+1的结点)
    p->next = t->next;
    //释放指针变量t指向的结点所占用的内存
    free(t);
    //使指针p、t指向NULL;
    t = NULL;
    p = NULL;
    //返回OK,表示删除成功
    return OK;

}

/**
 * 构造单链表
 * 使用前插法创建带有n个结点的单链表
 * 前插法:通过将新结点逐个插入链表的头部(头结点之后)来创建链表,每次申请一个新结点,读入相应的元素值,然后将新结点插入到头结点之后
 * 算法描述:
 * 1、为头结点申请动态内存,将动态内存的指针赋值给指针L指向头的指针,若申请失败,则返回OVERFLOW
 * 2、使用循环申请新结点的动态内存,若申请失败,返回OVERFLOW,若申请成功,给新建的数据域赋值并将新结点插入到头节点之后
 * 3、返回OK
 *
 *
 * @param L 指向单链表头指针的指针L
 * @param n 插入新结点的个数n
 * @return  操作结果状态码
 */
Status createLinkedListByInsertNewNodeAfterHeadNode(LinkedList *L, int n) {
    //为头结点申请动态内存,将动态内存的指针赋值给指针L指向头的指针
    *L = (LNode *) malloc(sizeof(LNode));
    //若申请失败,则返回OVERFLOW
    if (!*L)return OVERFLOW;
    (*L)->next = NULL;
    (*L)->data = 0;
    int i = 0;
    for (i = 0; i < n; ++i) {
        //申请新结点的动态内存
        LNode *p = (LNode *) malloc(sizeof(LNode));
        //若申请失败,返回OVERFLOW
        if (!p) return OVERFLOW;
        //若申请成功,给新建的数据域赋值并将新结点插入到头结点之后
        p->data = i + 1;
        p->next = (*L)->next;
        (*L)->next = p;
        p = NULL;
    }
    //返回OK
}

/**
 * 构造单链表
 * 使用后插法构造具有n个结点的单链表
 * 后插法:通过将新结点逐个插入到链表的尾部来创建链表。每次申请一个结点,读取相应的数据元素的值,为了使新结点能够插入到链表的尾部,需要增加一个尾指针r指向链表的尾结点
 * 算法描述:
 * 1、为头结点申请动态内存,将动态内存的指针赋值给指针L指向头的指针,若申请失败,则返回OVERFLOW
 * 2、定义尾指针r并使r指向头结点(即将头指针的值赋值给尾指针r)
 * 3、使用循环申请新结点的动态内存,若申请失败,返回OVERFLOW,若申请成功,给新建的数据域赋值并将新结点插入到尾结点之后,将尾指针r指向新插入的结点
 * 4、返回OK
 * @param L 指向单链表头指针的指针L
 * @param n 插入新结点的个数n
 * @return 操作结果状态码
 */
Status createLinkedListByInsertNewNodeAfterRearNode(LinkedList *L, int n) {
    //为头结点申请动态内存,将动态内存的指针赋值给指针L指向头的指针
    *L = (LNode *) malloc(sizeof(LNode));
    //若申请失败,则返回OVERFLOW
    if (!(*L)) return OVERFLOW;
    (*L)->next = NULL;
    (*L)->data = 0;
    //定义尾指针r并使r指向头结点(即将头指针的值赋值给尾指针r)
    LNode *r = *L;
    int i = 0;
    for (i = 0; i < n; i++) {
        //申请新结点的动态内存
        LNode *p = (LNode *) malloc(sizeof(LNode));
        //若申请失败,返回OVERFLOW
        if (!p)return OVERFLOW;
        //若申请成功,给新建的数据域赋值并将新结点插入到尾结点之后
        p->data = i + 1;
        p->next = NULL;
        r->next = p;
        //将尾指针r指向新插入的结点
        r = p;
        p = NULL;
    }
    r = NULL;
    return OK;
}

/**
 * 遍历单链表
 * 遍历单链表,依次输出每个结点的数据域的值
 * 算法描述:
 * 1、判断指针L是否合法,若不合法,返回ERROR
 * 2、定义指向当前结点的指针p并使p指向首元结点
 * 3、循环移动指针p并输出p指向的结点的数据域的值直至p=NULL(表示p指向尾结点的后继,即遍历结束)
 * 4、置指针p为NULL,返回OK
 * @param L 指向单链表的头结点的头指针
 * @return 操作结果状态码
 */
Status traverseList(LinkedList L) {
    //判断指针L是否合法,若不合法,返回ERROR
    if(!L){
        return ERROR;
    }
    //定义指向当前结点的指针p并使p指向首元结点
    LNode *p = L->next;
    //循环移动指针p并输出p指向的结点的数据域的值直至p = NULL(表示p指向尾结点的后继,即遍历结束)
    while (p){
        printElem(p->data);
        p = p->next;
    }
    //置指针p为NULL,返回OK
    //循环结束的条件就是p = NULL 故可以省略下一条语句
    p = NULL;
    return OK;
}

 

测试定义好的单链表和其基本操作的功能

int main() {
    LinkedList L = NULL;
    /*initLinkedList(&L);
    double d;
    if (insertLNode(&L, 1, 2.2)) {
        if (insertLNode(&L, 2, 3)) {
            if (getElem(&L, 1, &d)) {
                printf("%lf\n", d);
            }
        }
    }
    int i;
    d = 3.0;
    if (indexOf(L, &i, d)) {
        printf("%d\n", i);
    }
    LNode *p = locateElem(L, d);
    //查找成功,使用结点地址访问结点数据域
    //查找失败,输出结点地址,验证是否为NULL
    if (p) {
        printf("%lf\n", p->data);
    } else {
        printf("%d\n", p);
    }
    deleteNode(&L, 4);
    d = 3.0;
    if (indexOf(L, &i, d)) {
        printf("%d\n", i);
    } else {
        printf("%d\n", i);
    }*/

    //测试前插法
    /*if (createLinkedListByInsertNewNodeAfterHeadNode(&L, 10)) {
        double d;
        if (getElem(L, 7, &d)) {
            printf("%lf\n", d);
        }
    }*/

    //测试后插法
    if (createLinkedListByInsertNewNodeAfterRearNode(&L, 10)) {
        double d;
        if (getElem(L, 7, &d)) {
            printf("%lf\n", d);
        }
    }
    //测试销毁单链表
    /*destroyLinkedList(&L);*/

    //测试获取前趋和后继
    //测试前趋
    double curE = 1;
    LNode *prior = NULL;
    priorElem(L, curE, &prior);
    if (prior) {
        printf("The data of prior node of node which data is curE is %lf\n", prior->data);
    } else {
        printf("The node whose data i curE has not prior node!\n");
    }
    //测试后继
    LNode *next = NULL;
    curE = 9;
    nextElem(L, curE, &next);
    if (next) {
        printf("The data of next node of node which data is curE is %lf\n", next->data);
    } else {
        printf("The node whose data i curE has not next node!\n");
    }

    //测试遍历单链表
    traverseList(L);
    //测试清空单链表
    //测试判断单链表是否为空表
    int res = 0;
    isEmpty(L, &res);
    if (res) {
        printf("The LinkedList is a empty table.\n");
    } else {
        printf("The LinkedList isn‘t a empty table.\n");
    }
    //测试获取单链表长度
    int length = 0;
    getLength(L, &length);
    if (length < 0) {
        printf("The LinkedList has not been initialized or the LinkedList has been distroyed!\n");
    } else {
        printf("The LinkedList‘s length is %d!\n", length);
    }
    clearLinkedList(&L);
    //测试判断单链表是否为空表
    isEmpty(L, &res);
    if (res) {
        printf("The LinkedList is a empty table.\n");
    } else {
        printf("The LinkedList isn‘t a empty table.\n");
    }
    //测试获取单链表长度
    getLength(L, &length);
    if (length < 0) {
        printf("The LinkedList has not been initialized or the LinkedList has been distroyed!\n");
    } else {
        printf("The LinkedList‘s length is %d!\n", length);
    }
    if (L) {
        printf("The LinkedList has not been destroyed!");
        free(L);
    }
    next = NULL;
    prior = NULL;
    L = NULL;
    return 0;
}

 

之后可能会实现双链结构吧:)

C语言简单实现线性表的链式存储结构(单链结构)

标签:信息   linked   释放   元素   验证   sel   就是   etl   intel   

原文地址:https://www.cnblogs.com/RGBTH/p/13371316.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!