数据结构单链表操作

本小编是初学数据结构,如果有不对之处或者可改进之处,还望各位读者大哥海涵与告知,先双手源码奉上。

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

#define OK 1
#define ERROR -1
#define OK1 2
#define ERROR1 -2
#define OK2 3
#define ERROR2 -3
#define OK3 4
#define ERROR3 -4
#define KONG 5
#define NOKONG -5
#define OVER 6
#define NOFIND -6

typedef struct LNode {
    int data;              // 数据域
    struct LNode* next;    // 指针域
} LNode, *LinkList;

// 单链表初始化
int InitList_L(LinkList* L) {
    (*L) = (LinkList)malloc(sizeof(LNode));  // 分配头结点空间
    if (!(*L)) return ERROR;                 // 内存分配失败
    (*L)->next = NULL;                       // 头结点指针域置空
    return OK;
}

// 判断一个链表是否为空——判断头结点指针域是否为空
int ListEmpty(LinkList L) {
    if (L->next)
        return KONG;
    else
        return NOKONG;
}

// 单链表的销毁:链表销毁后不存在——从头指针开始,依次释放所有节点
int DestroyList(LinkList* L) {
    LNode* p;
    while (*L) {
        p = *L;
        *L = (*L)->next;
        free(p);
    }
    return OVER;
}

// 求单链表的表长——从首元结点开始,依次计数所有节点
int ListLength(LinkList L) {
    LinkList p;
    int count = 0;
    p = L->next;
    while (p) {
        count++;
        p = p->next;
    }
    return count;
}

// 取第i个元素的值——从链表的头指针出发,顺着链域next逐个向下搜索,直到搜索到第i个节点为止
// 特殊情况:1. i超过元素个数 2. i < 1
int GetElem_L(LinkList L, int i, int* e) {
    LinkList p = L->next;
    int j = 1;
    while (p && j < i) {
        p = p->next;
        j++;
    }
    if (!p || j > i)
        return ERROR1;  // 位置不合法
    *e = p->data;
    return OK1;
}

// 查找运算:按值查找位置(地址)——从第一个节点起依次与e比较
LinkList LocateElem_L(LinkList L, int e) {
    LinkList p = L->next;
    while (p && p->data != e)
        p = p->next;
    return p;
}

// 查找运算:按值查找位置序号(第几个)——从第一个节点起依次与e比较
int LocateElem_R(LinkList L, int e) {
    LinkList p = L->next;
    int j = 1;
    while (p && p->data != e) {
        p = p->next;
        j++;
    }
    if (p)
        return j;  // 返回位置序号
    else
        return NOFIND;  // 未找到元素
}

// 插入(在第i个节点前插入为e的新节点)
// 1. 找到i-1的存储位置p
// 2. 生成一个数据域为e的新节点s
// 3. 插入新节点(新节点的指针域指向节点i,节点i-1的指针域指向新节点)
int ListInsert_L(LinkList* L, int i, int e) {
    LinkList p = *L;
    int j = 1;
    while (p && j < i) {
        p = p->next;
        j++;
    }
    if (!p || j > i)
        return ERROR2;                          // 位置不合法
    LinkList s = (LinkList)malloc(sizeof(LNode));  // 生成新节点s
    s->data = e;
    s->next = p->next;                          // 插入新节点
    p->next = s;
    return OK2;
}

// 删除第i个节点
// 1. 找到i-1的存储位置p,保存要删除元素的值
// 2. 令p->next指向i+1
// 3. 释放i的空间
int ListDelete_L(LinkList* L, int i, int* e) {
    LinkList p = *L;
    int j = 0;
    while (p->next && j < i - 1) {
        p = p->next;
        j++;
    }  // 寻找第i个节点,并令p指向其前驱
    if (!(p->next) || j > i - 1)
        return ERROR3;                       // 删除位置不合理
    LinkList q = p->next;                    // 临时保存被删除节点的地址以备释放
    p->next = q->next;                       // 改变删除节点前驱的指针域
    *e = q->data;                            // 保存删除节点的数据域
    free(q);                                 // 释放删除节点的空间
    return OK3;
}

// 头插法
void CreateList_H(LinkList* L, int n) {
    (*L) = (LinkList)malloc(sizeof(LNode));  // 先建立一个带头结点的单链表
    (*L)->next = NULL;
    int i, value;
    printf("请依次输入%d个整数作为链表元素(从头插入): ", n);
    for (i = 0; i < n; ++i) {
        LinkList p = (LNode*)malloc(sizeof(LNode));  // 生成新节点p
        scanf("%d", &value);                          // 输入节点的值
        p->data = value;                               // 设置节点的值
        p->next = (*L)->next;                          // 插入到表头
        (*L)->next = p;
    }
}

//补充9:尾插法
void CreateList_R(LinkList* L, int n) {
    (*L) = (LinkList)malloc(sizeof(LNode));  // 先建立一个带头结点的单链表
    (*L)->next = NULL;
    LinkList r = *L;  // r用于指向尾节点
    int i;
    printf("请依次输入%d个整数作为链表元素(从尾插入): ", n);
    for (i = 0; i < n; ++i) {
        LinkList p = (LinkList)malloc(sizeof(LNode));  // 生成新节点p
        scanf("%d", &(p->data));                       // 输入节点的值
        p->next = NULL;                                // 新节点的指针域置空
        r->next = p;                                   // 插入到表尾
        r = p;                                         // 将尾节点指针指向新节点
    }
}

void PrintList(LinkList L) {
    L = L->next;  // 跳过头结点
    while (L != NULL) {
        printf("%d ", L->data);
        L = L->next;
    }
    printf("\n");
}

int main() {
    LinkList L;
    InitList_L(&L);  // 初始化链表

    int n;            // 输入链表长度
    printf("请输入链表长度: ");
    scanf("%d", &n);

    printf("请输入%d个整数作为链表元素: ", n);
    CreateList_R(&L, n);  // 使用头插法创建链表
    //CreateList_H(&L, n); 使用尾插法创建链表

    printf("链表元素为: ");
    PrintList(L);  // 打印链表元素

    int length = ListLength(L);  // 求链表长度
    printf("链表的长度为: %d\n", length);

    int value;
    printf("请输入要查找的元素值: ");
    scanf("%d", &value);
    LinkList pos = LocateElem_L(L, value);  // 按值查找节点位置
    if (pos) {
        printf("元素%d在链表中的位置为: %d\n", value, LocateElem_R(L, value));
    } else {
        printf("元素%d在链表中未找到\n", value);
    }

    int i;
    printf("请输入要获取的节点位置: ");
    scanf("%d", &i);
    int e;
    int status = GetElem_L(L, i, &e);  // 获取指定位置节点的值
    if (status == OK) {
        printf("第%d个节点的值为: %d\n", i, e);
    } else {
        printf("指定位置不存在节点\n");
    }

    int insertPos, insertValue;
    printf("请输入要插入的位置和值: ");
    scanf("%d %d", &insertPos, &insertValue);
    status = ListInsert_L(&L, insertPos, insertValue);  // 在指定位置插入节点
    if (status == OK) {
        printf("链表插入成功,插入后的元素为: ");
        PrintList(L);
    } else {
        printf("指定位置不合法\n");
    }

    int deletePos, deleteValue;
    printf("请输入要删除的位置: ");
    scanf("%d", &deletePos);
    status = ListDelete_L(&L, deletePos, &deleteValue);  // 删除指定位置节点
    if (status == OK) {
        printf("链表删除成功,删除节点的值为: %d,删除后的元素为: ", deleteValue);
        PrintList(L);
    } else {
        printf("指定位置不合法\n");
    }

    DestroyList(&L);  // 销毁链表
    if (!L) {
        printf("链表已销毁\n");
    }

    return 0;
}

如果您读完本文章,还请点一个小赞,支持小编继续学习,感谢感谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值