【线性表——链表】

一、写链表,主要需要两个结构体:

       一个是表头LinkList(只要知道了表头的地址,就能往下找到每一个结点;表头还记录结点长度)

       一个是结点LinkNode(包括数据域和指针域,每个结点都是通过指针域串联起来)

//表头
typedef struct LINKLIST{

    LinkNode* head;
    int size;

}LinkList;

//结点
typedef struct LINKNODE{

    void* data; //无类型指针,可以指向任何类型数据
    struct  LINKNODE* next;

}LinkNode;

 

注:图中的蓝色竖条代表结点LinkNode的地址

 

二、初始化链表

       初始化链表主要有两部分操作,一是为表头LinkList申请内存,二是为头结点LinkNode(Head) 申请内存。将头结点的地址赋    给表头的head,也就是说head相当于头结点LinkNode(Head) 。一切的操作都从head开始遍历。

//初始化链表

LinkList* Init_LinkList(){

    //创建表头 LinkList
    LinkList* list = (LinkList*)malloc(sizeof(LinkList));
    list->size = 0;

    //创建头结点 LinkNode(Head)
    list->head = (LinkNode*)malloc(sizeof(LinkNode));
    list->head->data = NULL;   //不保存数据信息
    list->head->next = NULL;

return list;
}

 

三、添加第1个结点

       申请内存创建新结点NewNode,填充数据data,next指向空地址NULL,然后将头结点LinkNode(Head)的next指新结点         NewNode的地址

//创建新的节点 LinkNode

LinkNode* NewNode = (LinkNode*)malloc(sizeof(LinkNode));

NewNode->data = data;

NewNode->next = NULL;



LinkNode* pCurrent = list->head;    //从头结点head开始操作

//新结点入链表

NewNode->next = pCurrent->next;   //这里的pCurrent->next(即头结点LinkNode(Head)的next)并没有指向任何一个结点,是指向NULL的

pCurrent->next = NewNode;



list->size++;    //表头记录长度

 

(声明:next代表的是下一个结点的地址。

例如:第n个结点的next就是第n+1个结点的地址

              第n个结点的next的next(相当于第n+1个结点的next)就是第n+2个结点的地址

 

 

四、插入新节点

       和第三步的添加第一个结点差不多,只不过原来头结点是指向空的,现在的情况是头结点指向了第1个结点,我们可以在头      结点和第1个结点之间插入一个新结点,也就是第0个位置上插入新结点(pos = 0)

//指定位置插入

void Insert_LinkList(LinkList* list,int pos,void* data){

    //创建新的节点 LinkNode
    LinkNode* NewNode = (LinkNode*)malloc(sizeof(LinkNode));
    NewNode->data = data;
    NewNode->next = NULL;

    LinkNode* pCurrent = list->head;
    for(int i= 0;i<pos;i++){       //这里的pos传入的值是0,因为是要在第0个位置上插入新结点
    pCurrent = pCurrent->next;    
    }

    //新结点入链表
    NewNode->next = pCurrent->next;
    pCurrent->next = NewNode;
    list->size++;
}

 

如果要想在第n个位置插入新结点,则

//指定位置插入

void Insert_LinkList(LinkList* list,int pos,void* data){



//创建新的节点 LinkNode

LinkNode* NewNode = (LinkNode*)malloc(sizeof(LinkNode));

NewNode->data = data;

NewNode->next = NULL;



LinkNode* pCurrent = list->head;

for(int i= 0;i<pos;i++){       //这里的pos传入的值是n,因为是要在第n个位置上插入新结点

pCurrent = pCurrent->next;     //遍历到第n-1个结点

}

//新结点入链表(新结点要取代第n个结点的位置,旧的第n个结点将变成第n+1个结点)

NewNode->next = pCurrent->next;   //将新结点的next指向第n个结点的地址(第n-1个结点的next就是第n个结点的地址)

pCurrent->next = NewNode;    //将第n-1个结点的next指向新结点的地址(或者说是:新节点的地址赋给第n-1个结点的next)



list->size++;

}

 

五、删除结点

假如要删除第n个结点,则只需将第n-1个结点的Next指向第n+1个结点的地址即可

void RemoveByPos_LinkList(LinkList* list,int pos){

//查找删除节点的前一个节点

LinkNode* pCurrent = list->head;

for(int i= 0;i<pos;i++){

pCurrent = pCurrent->next;   //遍历到第n-1个结点

}

LinkNode* pDel =  pCurrent->next;  //找到第n个结点的地址

pCurrent->next =  pDel->next;    //将第n-1个结点的Next指向第n+1个结点的地址



free(pDel);  //释放被删除的第n个节点的内存

list->size--;

}

 

六、销毁链表

            既然在插入结点的时候,每一个结点都是申请了内存,那么最后销毁链表的时候也应该一一释放掉每个结点的内存。

            结点释放顺序规则:

               ·从当前头结点head开始

               ·用指针pNext保存下一个结点的地址

               ·释放当前结点,保存pNext的下一个结点的地址

               ·释放当前结点,保存pNext的下一个结点的地址

            ..........

 

            当结点的内存都释放之后,就要处理表头list了:

               ·将list的size置零

               ·释放list的内存

               ·将list置NULL

//释放链表内存
void FreeSpace_LinkList(LinkList* list){
	if(list==NULL){
		return ; 
	} 
	LinkNode* pCurrent = list->head;
	while(pCurrent!=NULL){
		LinkNode* pNext =  pCurrent->next;
		free(pCurrent); 
		pCurrent = pNext; 
	} 

	//释放表头内存
	list->size = 0;
	free(list); 
	list = NULL;
} 

 

 

下面是完整的代码

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

//链表节点
typedef struct LINKNODE{
	void* data; //无类型指针,可以指向任何类型数据 
	struct  LINKNODE* next; 
}LinkNode; 

//链表结构体
typedef struct LINKLIST{
	LinkNode* head;
	int size; 
}LinkList; 

typedef struct PERSON{
	char name[64];
	int age; 
	int score; 
}Person; 

//打印函数指针 
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); 

/********************************************************************/ 

//初始化链表
LinkList* Init_LinkList(){
	//创建表头 LinkList
	LinkList* list = (LinkList*)malloc(sizeof(LinkList));
	list->size = 0;
	
	//创建头结点 LinkNode(Head) 不保存数据信息
	list->head = (LinkNode*)malloc(sizeof(LinkNode)); 
	list->head->data = NULL;
	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 = list->size; 
	} 
	
	//创建新的节点 LinkNode
	LinkNode* NewNode = (LinkNode*)malloc(sizeof(LinkNode));
	NewNode->data = data;
	NewNode->next = NULL;
	
	//找节点  辅助指针变量
	LinkNode* pCurrent = list->head;
	for(int 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; 
	}
	
	//查找删除节点的前一个节点
	LinkNode* pCurrent = list->head;
	for(int i= 0;i<pos;i++){
		pCurrent = pCurrent->next; 
	} 
	LinkNode* pDel =  pCurrent->next;
	pCurrent->next =  pDel->next; 
	//释放删除节点的内存
	free(pDel);
	list->size--; 
} 
//获得链表长度
int Size_LinkList(LinkList* list){
	
	return list->size; 
} 
//查找
int Find_LinkList(LinkList* list,void* data){
	if(list==NULL){
		return -1; 
	} 
	if(data==NULL){
		return -1; 
	}  
	LinkNode* pCurrent = list->head->next;
	int i; 
	for(i= 0;i<=list->size;i++){
		if(pCurrent->data==data){
			break; 
		} 
		pCurrent = pCurrent->next; 
	}  
	
	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;
	for(int i= 0;i<list->size;i++){
		print(pCurrent->data); 
		pCurrent = pCurrent->next; 
	}  
} 
//释放链表内存
void FreeSpace_LinkList(LinkList* list){
	if(list==NULL){
		return ; 
	} 
	LinkNode* pCurrent = list->head;
	while(pCurrent!=NULL){
		LinkNode* pNext =  pCurrent->next;
		free(pCurrent); 
		pCurrent = pNext; 
	} 

	//释放表头内存
	list->size = 0;
	free(list); 
	list = NULL;
} 
void MyPrint(void* data){
	Person* p =(Person*)data; 
	printf("Name:%s Age:%d Score%d \n",p->name,p->age,p->score); 
} 

/********************************************************************/ 
/********************************************************************/ 

void test01(){
	//创建链表
	LinkList* list =  Init_LinkList();
	
	//创建数据 
	Person p1 = {"a",16,100};
	Person p2 = {"b",17,101};
	Person p3 = {"c",18,102};
	Person p4 = {"d",19,103};
	Person p5 = {"e",20,104};
	
	//数据插入链表
	 Insert_LinkList(list,0,&p1); 
	 Insert_LinkList(list,1,&p2); 
	 Insert_LinkList(list,2,&p3); 
	 Insert_LinkList(list,3,&p4); 
	 Insert_LinkList(list,4,&p5); 
	 
	 //打印
	 Print_LinkList(list,MyPrint); 
	 printf("------------------------\n"); 
	 //删除
	RemoveByPos_LinkList(list,3); 
	//打印
	 Print_LinkList(list,MyPrint);
	 printf("------------------------\n"); 
	 //返回第一个节点
	 Person* ret = (Person*) Front_LinkList(list); 
	 printf("Name:%s Age:%d Score%d \n",ret->name,ret->age,ret->score); 
	 //销毁链表 
	 FreeSpace_LinkList(list);  

} 


/********************************************************************/ 
/********************************************************************/ 

int main(){
	test01(); 
	return 0; 
} 



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值