03黑马数据结构笔记之(单向)企业链表(小挂钩)
1 思路:链表不直接存放插入的整个数据,只存放数据的首地址,也就是我们自定义的小挂钩,实际上是一个节点,该节点只有一个用于连接数据的next指针。 例如我们在mian函数看数据插入时,将类型转为挂钩类型插入,链表一次将挂钩连接起来。
//小节点,即挂钩
typedef struct Node{
struct Node *next;
}SNode;
//大节点,即用来保存整个链表的结构体
typedef struct List{
SNode head; //挂钩对象,不需要在开辟内存了
int size;
}LinkList;
代码实现:
1)头文件.h:
#ifndef LINKLIST_H
#define LINKLIST_H
#include<stdio.h>
#include<stdlib.h>
//小节点,即挂钩
typedef struct Node{
struct Node *next;
}SNode;
//大节点,即用来保存整个链表的结构体
typedef struct List{
SNode head; //挂钩对象,不需要在开辟内存了
int size;
}LinkList;
//打印函数指针
typedef void(*PRINT)(SNode *);
typedef int(*MYCOMPARE)(SNode *s1,SNode *s2);
//初始化链表
LinkList *Init_LinkList();
//插入链表 插入时只需将数据的首地址传过来插入 打印时在转回全部打印
int Insert_LinkList(LinkList *list,int pos,SNode *data);
//删除
int Del_LinkList(LinkList *list,int pos);
//查找
int Find_LinkList(LinkList *list,MYCOMPARE myc,SNode *data);
//打印
int Printt_LinkLis(LinkList *list,PRINT print);
//返回链表大小
int Get_Size_LinkList(LinkList *list);
//释放内存
int Destory_LinkList(LinkList *list);
#endif
2).cpp文件:
#include"LinkList.h"
//初始化链表
LinkList *Init_LinkList(){
LinkList *list=(LinkList*)malloc(sizeof(LinkList));
list->size=0;
list->head.next=NULL; //对象不需要再赋值
return list;
}
//插入链表 插入时只需将数据的首地址传过来插入 打印时在转回全部打印
int Insert_LinkList(LinkList *list,int pos,SNode *data){
if(list==NULL){
return -1;
}
if(pos<0 || pos > list->size){
pos=list->size;
}
//查找插入点的前一个点--因为头结点不包含在size,且第一个有效节点下标为0。
//我之前写传统的代码是减1的,不怎么对,之前的数据以1开始下标,这里应该以0更好!!!
SNode *pPre=&(list->head);
for(int i=0;i<pos ;i++){
pPre=pPre->next;
}
//插入
SNode *pCur=pPre->next;
data->next=pCur;
pPre->next=data;
list->size++;
return 0;
}
//删除--根据下标删除
int Del_LinkList(LinkList *list,int pos){
if(list==NULL){
return -1;
}
//找到要删除的前一节点 注意是按下标的,所以pos不需要减1了
SNode *pPre=&(list->head);
for(int i=0;i<pos ;i++){
pPre=pPre->next;
}
//删除
pPre->next=pPre->next->next;
list->size--;
return 0;
}
//查找
int Find_LinkList(LinkList *list,MYCOMPARE myc,SNode *data){
if(list==NULL){
return -1;
}
if(data==NULL){
return -1;
}
SNode *pCur=list->head.next;
int count=0; //注意:头结点不包含在size,且第一个有效节点下标为0
while(pCur!=NULL){
//需要使用到自定义函数查找,所以需要函数指针
if(myc(pCur,data)){
break;
}
pCur=pCur->next;
count++;
}
if(count==list->size){
printf("没找到而退出\n");
return -1;
}
return count;
}
//打印
int Printt_LinkLis(LinkList *list,PRINT print){
if(list==NULL){
return -1;
}
SNode *pCur=list->head.next;
while(pCur!=NULL){
print(pCur);
pCur=pCur->next;
}
return 0;
}
//返回链表大小
int Get_Size_LinkList(LinkList *list){
return list->size;
}
//释放内存
int Destory_LinkList(LinkList *list){
if(list==NULL){
return -1;
}
//只有链表的结构体需要释放
free(list);
return 0;
}
3)主函数测试:
#include"LinkList.h"
#include<string>
typedef struct Person{
SNode *node;
char name[64];
int age;
}Person;
//打印自定义回调函数
void MyPrint(SNode *s){
Person *p=(Person*)s; //将SNode*型转回自定义类型打印
printf("名字:%s,年龄:%d\n",p->name,p->age);
}
//查找自定义回调函数
int MyCompare(SNode *s1,SNode *s2){
Person *p1=(Person*)s1;
Person *p2=(Person*)s2;
if(strcmp(p1->name,p2->name)==0 && p1->age==p2->age){
return 1; //返回1代表相等找到了
}
return 0;
}
void test02(){
//创建结构体链表
LinkList *list=Init_LinkList();
//创建数据
Person p1;
Person p2;
Person p3;
Person p4;
Person p5;
strcpy(p1.name,"aaa");
strcpy(p2.name,"bbb");
strcpy(p3.name,"ccc");
strcpy(p4.name,"ddd");
strcpy(p5.name,"eee");
p1.age=18;
p2.age=20;
p3.age=32;
p4.age=28;
p5.age=19;
//插入数据 插入时只需传挂钩就可以 链表实际上只存放挂钩的地址 需要打印数据在转化成相应类型
Insert_LinkList(list,0,(SNode*)&p1);
Insert_LinkList(list,0,(SNode*)&p2);
Insert_LinkList(list,0,(SNode*)&p3);
Insert_LinkList(list,0,(SNode*)&p4);
Insert_LinkList(list,0,(SNode*)&p5);
//打印链表
Printt_LinkLis(list,MyPrint);
//根据数据查找链表节点
int pos=Find_LinkList(list,MyCompare,(SNode*)&p3);
printf("查到返回的下标是:%d\n",pos); //2
//删除
Del_LinkList(list,2);
Printt_LinkLis(list,MyPrint);
//返回链表大小
int size=Get_Size_LinkList(list);
printf("链表大小:%d\n",size);
//销毁链表
Destory_LinkList(list);
}
int main(){
test02();
return 0;
}
//总结:主要是要懂企业链表的思想.将节点放在首地址