最近整理了一下以前的数据结构,一下为单链表的所有笔记,全部替换为标准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;
}