ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线性表(二)单链表

2022-09-04 03:30:28  阅读:186  来源: 互联网

标签:Status 单链 return 线性表 ElemType next LinkList NULL


单链表

LinkList.h

typedef int ElemType;

typedef struct{
   ElemType data;//数据结点
   struct LNode* next;//指向下一个结点的指针
} LNode;

typedef LNode* LinkList;

Status InitList(LinkList* L);
Status DestroyList(LinkList* L);
Status CearList(LinkList L);
Status ListEmpty(LinkList L);
int ListLength(LinkList L);
Status GetElem(LinkList L, int i, ElemType* e);
int LocateElem(LinkList L, ElemType e, Status(Compare)(ElemType, ElemType));
Status PriorElem(LinkList L, ElemType cur_e, ElemType* pre_e);
Status NextElem(LinkList L, ElemType cur_e, ElemType* next_e);
Status ListInsert(LinkList L, int i, ElemType e);
Status ListDelete(LinkList L, int i, ElemType* e);
void ListTraverse(LinkList L, void(Visit)(ElemType));

LinkList.c

#include "LinkList.h"

/*
 * 初始化(头结点)
 *
 */
Status InitList(LinkList* L) {
    (*L) = (LinkList) malloc(sizeof(LNode));
    if(*L == NULL) {
        exit(OVERFLOW);
    }
    
    (*L)->next = NULL;
    
    return OK;
}

/*
 * 销毁(结构)
 *
 * 释放链表所占内存,头结点也会被清理。
 */
Status DestroyList(LinkList* L) {
    LinkList p;
    
    // 确保链表结构存在
    if(L == NULL || *L == NULL) {
        return ERROR;
    }
    
    p = *L;
    
    while(p != NULL) {
        p = (*L)->next;
        free(*L);
        (*L) = p;
    }
    
    *L = NULL;
    
    return OK;
}

/*
 * 置空(内容)
 *
 * 这里需要释放链表中非头结点处的空间。
 */
Status ClearList(LinkList L) {
    LinkList pre, p;
    
    // 确保链表存在
    if(L == NULL) {
        return ERROR;
    }
    
    p = L->next;
    
    // 释放链表上所有结点所占内存
    while(p != NULL) {
        pre = p;
        p = p->next;
        free(pre);
    }
    
    L->next = NULL;
    
    return OK;
}

/*
 * 判空
 *
 */
Status ListEmpty(LinkList L) {
    // 链表只有头结点时,认为该链表为空
    if(L != NULL && L->next == NULL) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/*
 * 计数
 */
int ListLength(LinkList L) {
    LinkList p;
    int i;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return 0;
    }
    
    i = 0;
    p = L->next;
    
    // 遍历所有结点
    while(p != NULL) {
        i++;
        p = p->next;
    }
    
    return i;
}

/*
 * 取值
 */
Status GetElem(LinkList L, int i, ElemType* e) {
    LinkList p;
    int j;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return ERROR;
    }
    
    p = L;
    j = 0;
    
    // 寻找第i-1个结点,且保证该结点的后继不为NULL
    while(p->next != NULL && j < i - 1) {
        p = p->next;
        ++j;
    }
    
    // 如果遍历到头了,或者i的值不合规(比如i<=0),说明没找到合乎目标的结点
    if(p->next == NULL || j > i - 1) {
        return ERROR;
    }
    
    *e = p->next->data;
    
    return OK;
}

/*
 * 查找
 *
 * 返回链表中首个与e满足Compare关系的元素位序。
 * 如果不存在这样的元素,则返回0。
 *
 *【备注】
 * 元素e是Compare函数第二个形参
 */
int LocateElem(LinkList L, ElemType e, Status(Compare)(ElemType, ElemType)) {
    int i;
    LinkList p;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return 0;
    }
    
    i = 1;          // i的初值为第1个元素的位序
    p = L->next;    // p的初值为第1个元素的指针
    
    while(p != NULL && !Compare(p->data, e)) {
        i++;
        p = p->next;
    }
    
    if(p != NULL) {
        return i;
    } else {
        return 0;
    }
}

/*
 * 前驱
 *
 * 获取元素cur_e的前驱,
 * 如果存在,将其存储到pre_e中,返回OK,
 * 如果不存在,则返回ERROR。
 */
Status PriorElem(LinkList L, ElemType cur_e, ElemType* pre_e) {
    LinkList pre, next;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return ERROR;
    }
    
    // 指向第1个元素
    pre = L->next;
    
    // 第1个元素没有前驱
    if(pre->data == cur_e) {
        return ERROR;
    }
    
    // 指向第2个元素
    next = pre->next;
    
    // 从第2个元素开始,查找cur_e的位置
    while(next != NULL && next->data != cur_e) {
        pre = next;
        next = next->next;
    }
    
    // 如果没找到元素cur_e,查找失败,返回ERROR
    if(next == NULL) {
        return ERROR;
    }
    
    *pre_e = pre->data;
    
    return OK;
}

/*
 * 后继
 *
 * 获取元素cur_e的后继,
 * 如果存在,将其存储到next_e中,返回OK,
 * 如果不存在,则返回ERROR。
 */
Status NextElem(LinkList L, ElemType cur_e, ElemType* next_e) {
    LinkList pre;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return ERROR;
    }
    
    // 指向第1个元素
    pre = L->next;
    
    // 从第1个元素开始,查找cur_e的位置,且保证该结点的后继不为NULL
    while(pre->next != NULL && pre->data != cur_e) {
        pre = pre->next;
    }
    
    // 如果没找到cur_e,或者找到了,但它没有后继,均返回ERROR
    if(pre->next == NULL) {
        return ERROR;
    }
    
    *next_e = pre->next->data;
    
    return OK;
}

/*
 * 插入
 *
 */
Status ListInsert(LinkList L, int i, ElemType e) {
    LinkList p, s;
    int j;
    
    // 确保链表存
    if(L == NULL) {
        return ERROR;
    }
    
    p = L;
    j = 0;
    
    // 寻找第i-1个结点,且保证该结点本身不为NULL
    while(p != NULL && j < i - 1) {
        p = p->next;
        ++j;
    }
    
    // 如果遍历到头了,或者i的值不合规(比如i<=0),说明没找到合乎目标的结点
    if(p == NULL || j > i - 1) {
        return ERROR;
    }
    
    // 生成新结点
    s = (LinkList) malloc(sizeof(LNode));
    if(s == NULL) {
        exit(OVERFLOW);
    }
    s->data = e;
    s->next = p->next;
    p->next = s;
    
    return OK;
}

/*
 * 删除
 */
Status ListDelete(LinkList L, int i, ElemType* e) {
    LinkList p, q;
    int j;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return ERROR;
    }
    
    p = L;
    j = 0;
    
    // 寻找第i-1个结点,且保证该结点的后继不为NULL
    while(p->next != NULL && j < i - 1) {
        p = p->next;
        ++j;
    }
    
    // 如果遍历到头了,或者i的值不合规(比如i<=0),说明没找到合乎目标的结点
    if(p->next == NULL || j > i - 1) {
        return ERROR;
    }
    
    // 删除第i个结点
    q = p->next;
    p->next = q->next;
    *e = q->data;
    free(q);
    
    return OK;
}

/*
 * 遍历
 *
 * 用visit函数访问链表L
 */
void ListTraverse(LinkList L, void(Visit)(ElemType)) {
    LinkList p;
    
    // 确保链表存在且不为空表
    if(L == NULL || L->next == NULL) {
        return;
    }
    
    p = L->next;
    
    while(p != NULL) {
        Visit(p->data);
        p = p->next;
    }
    
    printf("\n");
}

/*
 * 头插法创建链表
 *
 *
 *【备注】
 *
 * 教材中默认从控制台读取数据。
 * 这里为了方便测试,避免每次运行都手动输入数据,
 * 因而允许选择从预设的文件path中读取测试数据。
 *
 * 如果需要从控制台读取数据,则path为NULL或者为空串,
 * 如果需要从文件中读取数据,则需要在path中填写文件名信息。
 */
Status CreateList_Head(LinkList* L, int n, char* path) {
    int i;
    LinkList p;
    FILE* fp;
    int readFromConsole;    // 是否从控制台读取数据
    
    // 如果没有文件路径信息,则从控制台读取输入
    readFromConsole = path == NULL || strcmp(path, "") == 0;
    
    if(readFromConsole) {
        // 建立头结点
        *L = (LinkList) malloc(sizeof(LNode));
        (*L)->next = NULL;
        
        printf("请输入%d个降序元素:", n);
        
        for(i = 1; i <= n; ++i) {
            // 生成新结点
            p = (LinkList) malloc(sizeof(LNode));
            
            // 填充数据,并插入到链表中
            scanf("%d", &(p->data));
            
            p->next = (*L)->next;
            (*L)->next = p;
        }
    } else {
        // 打开文件,准备读取测试数据
        fp = fopen(path, "r");
        if(fp == NULL) {
            return ERROR;
        }
        
        // 建立头结点
        *L = (LinkList) malloc(sizeof(LNode));
        (*L)->next = NULL;
        
        for(i = 1; i <= n; ++i) {
            // 生成新结点
            p = (LinkList) malloc(sizeof(LNode));
            
            // 填充数据,并插入到链表中
            ReadData(fp, "%d", &(p->data));
            
            p->next = (*L)->next;
            (*L)->next = p;
        }
        
        fclose(fp);
    }
    
    return OK;
}

/*
 * 尾插法创建链表
 *
 *
 *【备注】
 *
 * 教材中默认从控制台读取数据。
 * 这里为了方便测试,避免每次运行都手动输入数据,
 * 因而允许选择从预设的文件path中读取测试数据。
 *
 * 如果需要从控制台读取数据,则path为NULL或者为空串,
 * 如果需要从文件中读取数据,则需要在path中填写文件名信息。
 */
Status CreateList_Tail(LinkList* L, int n, char* path) {
    int i;
    LinkList p, q;
    FILE* fp;
    int readFromConsole;    // 是否从控制台读取数据
    
    // 如果没有文件路径信息,则从控制台读取输入
    readFromConsole = path == NULL || strcmp(path, "") == 0;
    
    if(readFromConsole) {
        // 建立头结点
        *L = (LinkList) malloc(sizeof(LNode));
        (*L)->next = NULL;
        
        printf("请输入%d个升序元素:", n);
        
        for(i = 1, q = *L; i <= n; ++i) {
            // 生成新结点
            p = (LinkList) malloc(sizeof(LNode));
            
            // 填充数据,并插入到链表中
            scanf("%d", &(p->data));
            
            q->next = p;
            q = q->next;
        }
        
        q->next = NULL;
    } else {
        // 打开文件,准备读取测试数据
        fp = fopen(path, "r");
        if(fp == NULL) {
            return ERROR;
        }
        
        // 建立头结点
        *L = (LinkList) malloc(sizeof(LNode));
        (*L)->next = NULL;
        
        for(i = 1, q = *L; i <= n; ++i) {
            // 生成新结点
            p = (LinkList) malloc(sizeof(LNode));
            
            // 填充数据,并插入到链表中
            ReadData(fp, "%d", &(p->data));
            
            q->next = p;
            q = q->next;
        }
        
        q->next = NULL;
        
        fclose(fp);
    }
    
    return OK;
}

 

标签:Status,单链,return,线性表,ElemType,next,LinkList,NULL
来源: https://www.cnblogs.com/jdbc2nju/p/16654169.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有