C语言 - 基础数据结构和算法 - 单向链表
阅读原文时间:2023年07月09日阅读:1

听黑马程序员教程《基础数据结构和算法 (C版本)》,照着老师所讲抄的,

视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1

喜欢的朋友可以去看看。

02 单向链表

#include
#include
#include

// 用户自定义数据
typedef struct Student{
int id; // 学号
char name[32]; // 姓名
char classs[32]; // 班级
int ch,ma,en; // 语、数、外、总分
}st;

// 链表结点
typedef struct LINKNODE{
//int i_data; // 这样写就写死了,只能放int数据了,
void* data; // void* 是无类型指针,可以指向任何类型的数据。
struct LINKNODE* next;
}LinkNode;

// 链表结构体
typedef struct LINKLIST{
LinkNode* head; // 头结点
int size; // 链表节点数
// 要像动态数组一样需要内存容量吗?不需要, 没有容量概念。
}LinkList;

// 打印函数指针
typedef void(*PRINTLINKNODE)(void*);

// -----------------------------------------------------------------------------
// 下面函数,就是针对上面链表结构体和结点的操作。
// -----------------------------------------------------------------------------

// 初始化链表 ,返回一个链表结构体
LinkList* Init_LinkList();

// 指定位置插入。参数:所插入的链表,位置,值
void Insert_LinkList(LinkList* list,int pos,void* data);

// 删除指定位置的值。 参数:链表,位置
void RemoveByPos_LinkLIst(LinkList* list,int pos);

// 获得链表的长度(结点数量)
int Size_LinkList(LinkList* list);

// 根据值,查找位置
int Find_LinkList(LinkList* list,void* data);

// 返回第一个节点
void* Front_LinkList(LinkList* list);

// 打印链表结点
void Print_LinkList(LinkList* list,PRINTLINKNODE print);

// 释放内存
void FreeSpace_LinkList(LinkList* list);

// ----------------------------------- main() --------------------

// 打印函数
void MyPrint(void* data){
st* p = (st*)data;
printf("学号:%d\t姓名:%s\t班级:%s\t语文%d\t数学%d\t英语%d\t总分%d\n",
p->id,p->name,p->classs,p->ch,p->ma,p->en,p->ch+p->ma+p->en);
}
int main(){
printf("好好学习,天天向上~!(单向链表20220603)\n\n");

// 创建链表  
LinkList\* stList = Init\_LinkList();

// 创建数据  
st st1 = {2001,"宗宗","364班",100,100,100};  
st st2 = {2002,"艳艳","364班",99,88,59};  
st st3 = {2003,"发发","364班",88,77,66};  
st st4 = {2004,"小小","364班",58,57,55};  
st st5 = {2005,"小五","364班",58,57,55};

// 插入数据  
Insert\_LinkList(stList,0,&st1);  
Insert\_LinkList(stList,0,&st2);  
Insert\_LinkList(stList,0,&st3);  
Insert\_LinkList(stList,0,&st4);  
Insert\_LinkList(stList,0,&st5);

// 打印  
Print\_LinkList(stList,MyPrint); 

printf("\\n删除第3个节点\\n");  
RemoveByPos\_LinkLIst(stList,3);  
// 打印  
Print\_LinkList(stList,MyPrint);

printf("\\n返回第一个节点\\n");  
// 返回的是void\* 类型,要转换成st\*类型  
st\* ret = (st\*)Front\_LinkList(stList);  
printf("学号:%d\\t姓名:%s\\t班级:%s\\t语文%d\\t数学%d\\t英语%d\\t总分%d\\n",  
            ret->id,ret->name,ret->classs,ret->ch,ret->ma,ret->en,ret->ch+ret->ma+ret->en);    

// 销毁释放  
FreeSpace\_LinkList(stList);  
return 0;  

}

// -----------------------------------------------------------------------------
// 下面函数,就是针对上面链表结构体和结点的操作。
// -----------------------------------------------------------------------------

// 初始化链表 ,返回一个链表结构体
LinkList* Init_LinkList(){
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
// 添加头节点,头节点不保存数据
list->head = (LinkNode*)malloc(sizeof(LinkNode));
list->head->next = NULL; // 头结点初始化一下

return list;  

}

// 指定位置插入。参数:所插入的链表,位置,值(是数据指针)
void Insert_LinkList(LinkList* list,int pos,void* data){

// 判断检查参数  
if(list==NULL){  
    return;  
}  
if(data==NULL){  
    return;  
}  
if(pos<0 || pos > list->size){    // 友好判断,如果位置pos越界,由插入到尾部  
    pos = list->size;  
}

// 创建新的节点  
LinkNode\* newNode = (LinkNode\*)malloc(sizeof(LinkNode));  
newNode->data = data;    // 新节点赋值

// 找结点  
LinkNode\* pCurrent =  list->head;    // 辅助指针,用于找当前节点(插入位置的前一个节点)  
int i;  
for(i=0;i<pos;i++){        // 通过循环找到插入位置的前一个节点  
    pCurrent = pCurrent->next;  
}  
// 插入  
newNode->next = pCurrent->next;  
pCurrent->next = newNode;

list->size++;    // 更新节点数量的记录。 

}

// 删除指定位置的值。 参数:链表,位置
void RemoveByPos_LinkLIst(LinkList* list,int pos){
// 判断检查参数
if(list==NULL){
return;
}
if(pos<0 || pos >= list->size){
//pos = list->size; // 这里就不能友好判断了,
return; // 指定位置不存在,直接返回。
}

// 删除  
// 找结点  
LinkNode\* pCurrent =  list->head;    // 辅助指针,用于找当前节点(删除节点的前一个节点)  
int i;  
for(i=0;i<pos;i++){        // 通过循环找到要删除结点的前一个节点  
    pCurrent = pCurrent->next;  
}  
// 删除(先缓存要删除的节点)  
//pCurrent->next = pCurrent->next->next;  
//free(pCurrent->next);  
LinkNode\* pDel = pCurrent->next;  
pCurrent->next = pDel->next;  
free(pDel);  
list->size--;    // 更新链表节点数量 

}

// 获得链表的长度(结点数量)
int Size_LinkList(LinkList* list){

return -1;  

}

// 根据地址,查找位置,void* data 是地址(指针),不是值。
int Find_LinkList(LinkList* list,void* data){
// 判断检查参数
if(list==NULL){
return -1;
}
if(data==NULL){
return -1;
}

// 遍列查找节点,从头节点的下一个节点开始找  
LinkNode\* pCurrent = list->head->next;  
int i = 0;  
while(pCurrent){  
    if(pCurrent->data==data){  
        break;  
    }  
    pCurrent = pCurrent->next;  
    i++;  
}

return i;  

}

// 返回第一个节点
void* Front_LinkList(LinkList* list){
return list->head->next->data;
}

// 打印链表结点
void Print_LinkList(LinkList* list,PRINTLINKNODE print){
if(list==NULL){
return;
}
// 辅助指针变量
LinkNode* pCurrent = list->head->next;
while(pCurrent){
print(pCurrent->data); // 调用用户函数,传入数据参数
pCurrent = pCurrent->next;
}

}

// 释放内存
void FreeSpace_LinkList(LinkList* list){
if(list==NULL){
return;
}
// 辅助指针变量
LinkNode* pCurrent = list->head;
while(pCurrent){ // 循环释放节点内存。
LinkNode* pNext = pCurrent->next; // 用指针先记录下一个节点,如果不记录的话,释放内存后就没有了,
free(pCurrent);
pCurrent = pNext;
}
free(list); // 节点内存释放完毕后,再释放链表内存
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章