【学习记录】 单链表整理

最近整理了一下以前的数据结构,一下为单链表的所有笔记,全部替换为标准c语言的方式。
若有修改会在本文后面赘述


typedef struct {
    int name;
    void * pp;
}data;//数据域的结构类型
typedef struct link {//单链表的数据结构
    data Ldata;
    struct link* next;//好像这里不能用LNode来定义,因为这就是在定义LNode
}LNode;



//初始化一个链表(建立头节点)
LNode* List_init(void) {
    LNode* p;
    p = (LNode*)malloc(sizeof(LNode));
    if (!p) return 0;//内存不足分配失败
    else {
        p->next = NULL;
        return p;
    }
}


//判断一个单链表是否为空表
int ListEmpty(LNode* L) {
    if (L->next == NULL)
        return 1;//表示为空
    else
        return 0;
}
//头节点也释放
//销毁单链表
int DestoryList_L(LNode* L) {
    LNode* p;//或者LinkList p
    while (L) {//L!=NULL
        p = L;//先将L指向的结点给P
        L = L->next;//然后L指向下一个节点
        free(p);//删除刚刚的节点
    }//循环直到L指向空(NULL)
    return 1;
}
//只释放后面的
//清空一个单链表
int ClearList(LNode* L) {
    LNode* p, * q;//定义两个中间变量指针
    p = L->next;//指向第一个节点   p=L为首元节点
    q = p;//这一步是为了避免报错,先将q给一个初值
    while (p != NULL) {//或者条件为p也行
        q = q->next;//q提前指向下一个
        free(p);//释放p
        p = q;//此时如果指向的下一个为空则结束循环,不为空则继续
    }
    L->next = NULL;//第一个节点已经被释放,将头节点的next设置为空
    return 1;
}

//获取某个节点的数据区,通过data接收
int GetElem_L(LNode* L, int i, data* data) {
    LNode* p;//中间指针变量
    int j = 0;//用于记录找到第几个节点了
    p = L->next;//首先指向第一个节点,即这里不算首元节点,将我们定义的第一个当作第一个节点
    j = 1;
    while (p && j < i) {//一直往下找,直到这俩条件有一个不成立,即 p为空或者 i==j
        /*题外话,这里开始我将j<i写成i<j了,可让我好找这个该死的bug*/
        p = p->next;
        j++;
    }
    if (!p || j > i)//这里已经退出循环,这俩条件有一个成立就代表没找到,出错了,即 p为空或者 j>i(i=-1,0等不合法数值)
        return 0;
    *data = p->Ldata;//返回当前节点的数据区,由data接收
    return 1;
}

//返回链表的长度.i=0,则不算头节点,i=1,则算头节点
int ListLength(LNode* L) {
    LNode* p;
    int i = 0;
    p = L->next;
    while (p) {
        p = p->next;
        i++;
    }
    return i;
}
//在单链表中按照数据域中的某个值来查找响应节点,返回对应节点的地址
LNode* LocateElem_L_P(LNode* L, int nam) {
    //这里举例查找data中name的值
    LNode* p;
    p = L->next;
    while (p && p->Ldata.name != nam) {
        p = p->next;
    }
    return p;//这一步如果找到了刚好返回的是对应节点的地址,如果没找到刚好是NULL
}

//在单链表中按照第几个节点来查找响应节点,返回对应节点的地址
LNode* LocateElem_LN_P(LNode* L, int n) {
    LNode* p;
    p = L->next;//指向第一个节点
    int i = 1;
    while (p && i < n) {
        p = p->next;
        i++;
    }
    return p;//这一步如果找到了刚好返回的是对应节点的地址,如果没找到刚好是NULL
}


//在单链表中按照数据域中的某个值来查找响应节点,返回对应节点的序号
int LocateElem_L_N(LNode* L, int nam) {
    //这里举例查找data中name的值
    LNode* p;
    p = L->next;
    int j = 1;
    while (p && p->Ldata.name != nam) {
        p = p->next;
        j++;
    }
    if (p) return j;//如果p不为空则是找到了,返回对应的序号
    else  return 0;//反之返回0,表示没找到
}
/**
  * @brief 在第i个节点之前插入一个新节点
  *       (注意引用&是c++中的语法,在C语言中要以指针替换)
  * @param  i: 表示第几个节点
  * @param  dat: 用dat来存储增加节点数据域的数据
  * @retval 0 错误 1成功
  */
int ListInsert_L(LNode* L, int i, data dat)//,数据域用传入的dat
{
    LNode* p;
    int j = 0;
    p = L;//p指向首元节点
    while (p && j < i - 1) {
        p = p->next;
        j++;
    }
    if (!p || j > i - 1) return 0;
    LNode* s;
    s = (LNode*)malloc(sizeof(LNode));
    if (s == NULL) return 0;
    s->Ldata = dat;
    s->next = p->next;//将新建的节点指向后面的节点,把原来i位置的后面的地址赋值
    p->next = s;//将原来i位置的节点指向新建的节点
    return 1;
}
/**
  * @brief 将链表中第i个元素删除
  *       (注意引用&是c++中的语法,在C语言中要以指针替换)
  * @param  i: 表示删除第几个元素
  * @param  dat: 用dat来存储被删除数据的数据域
  * @retval 0 错误 1成功
  */
int ListDelete_L(LNode* L, int i, data* dat) {//将链表中第i个元素删除,用dat来存储被删除数据的数据域
    LNode* p, * q; int j = 0;
    p = L;
    while (p->next && j < i - 1) {
        p = p->next;
        j++;
    }
    if (!(p->next) || j > i - 1) return 0;
    q = p->next;//保存被删除节点的地址
    p->next = q->next;//将前驱节点指向后面的节点
    *dat = q->Ldata;//保存被删除节点的数据域
    free(q);//释放内存
    return 1;
}

/**
  * @brief 用头插法来建立一个链表,这里我做了一些修改
  *        原版是在函数内部给 L分配空间,这里我并没有这样做
  *        因此在使用该函数之前必须要调用List_init()来为L分配空间
  *       (注意引用&是c++中的语法,在C语言中要以指针替换)
  * @param  L: LNode*  pp 定义的一个指针,指向头节点
  * @param  dat: data 类型的数据域结构体,用于给新建节点的数据域赋值
  * @retval 0 错误 1成功
  */
int CreateList_H(LNode* L, data* dat) {
    if (L == NULL)//检查L是否为空
        return 0;//表示传入的L并没有分配空间
    LNode* p;
    p = (LNode*)malloc(sizeof(LNode));//创建一个新节点
    if (p == NULL) return 0;
    p->Ldata = *dat;//将数据放入数据域
    p->next = L->next;//将头节点之后的元素放到新建节点后
    L->next = p;//将新节点放入头节点后
    return 1;
}
/**
  * @brief 用尾插法来建立一个链表,
  *        原版是在函数内部给 L分配空间,这里我并没有这样做
  *        因此在使用该函数之前必须要调用List_init()来为L分配空间
  *       (注意引用&是c++中的语法,在C语言中要以指针替换)
  * @param  L: LNode*  pp 定义的一个指针,指向头节点
  * @param  dat: data 类型的数据域结构体,用于给新建节点的数据域赋值
  * @retval 0 错误 1成功
  */
int CreateList_R(LNode* L, data* dat) {
    if (L == NULL)//检查L是否为空
        return 0;//表示传入的L并没有分配空间
    LNode* p;//新建的节点
    LNode* q; //用来寻找最后一个节点
    q = L;
    p = (LNode*)malloc(sizeof(LNode));//创建一个新节点
    if (p == NULL) return 0;//创建新节点失败
    p->Ldata = *dat;//将数据放入数据域
    p->next = NULL;//将新建节点的后继指针置空
    while (q->next) {//找到最后一个节点
        q = q->next;
    }
    q->next = p;//将新建的节点接在后面
    return 1;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值