1.今天讲的主要是 循环链表
2.知识点主要在 代码里
一,老师代码:(有六个文件 )
1.student.c
#include "student.h"
void student_updata_sex(void* data1,const void* data2)
{
pstu ptemp1 = (pstu)data1;
const pstu ptemp2 = (const pstu)data2;
ptemp1->m_sex = ptemp2->m_sex;
}
student.h
#ifndef _STUDENT_H__
#define _STUDENT_H__
typedef struct student
{
char name[20];
int m_id;
int m_age;
char m_sex:1;
int m_English; //个人的英语成绩
}stu,*pstu;
#endif
node.c
#include "node.h"
/********
* 函数名:create_node
* 参 数:无
* 返回值:返回链表的首地址
* 功 能:创建一个链表,链表头
*/
node_t* create_node()
{
//第一步:申请头节点
node_t* head = (node_t*)malloc(sizeof(node_t));
if(NULL == head)
{
printf("头节点申请错误\n");
return NULL;
}
//第二步:给头节点数据赋值
head->data = NULL;
head->next = head;
head->prev = head;
return head;
}
/****************************
* 函数名:node_insert_end
* 参数:
* head: 头节点指针
* data:需要插入的数据指针
* size:x需要插入的数据大小
* 返回值:返回错误信息
* 作 用: 在双向链表尾部添加节点
* data 有内存,但没值.
***************************************/
int node_insert_end(node_t* head,void* data,int size)
{
// 第一步:判断各类指针是否有错
if(NULL == head)
{
return node_insert_error1;//首地址错误
}
if(NULL == data )
{
return node_insert_error2; //传递数据指针错误
}
//第二步:申请新节点
node_t* node_new = (node_t*)malloc(sizeof(node_t));
if(NULL == node_new)
{
return node_insert_error4;
}
//第三步:给新节点的data数据域指针申请内存
node_new->data = malloc(size);
if(node_new->data == NULL)
{
return node_insert_error4;
}
//第四步:给数据域指针指向内存拷贝数据
memcpy(node_new->data,data,size);//内存拷贝
//第五步:尾指针的next指向新节点
head->prev->next = node_new;
//第六步:新节点的前指针指向尾节点
node_new->prev = head->prev;
//第七步:头节点的前指针指向最后一个节点(node_new)
head->prev = node_new;
//第八步:最后一个节点next指针指向头节点
node_new->next = head;
return node_insert_error0;
}
/****************************
* 函数名:node_insert_start
* 参数:
* head: 头节点指针
* data: 需要插入的数据指针
* size: 需要插入的数据大小
* 返回值:返回错误信息
* 作 用: 在双向链表头部添加节点,在hed节点的下一个节点插入
***************************************/
int node_inset_start(node_t* head,void* data,int size)
{
// 第一步:判断各类指针是否有错
if(NULL == head)
{
return node_insert_error1;//首地址错误
}
if(NULL == data )
{
return node_insert_error2; //传递数据指针错误
}
//第二步:申请新节点
node_t* node_new = (node_t*)malloc(sizeof(node_t));
if(NULL == node_new)
{
return node_insert_error4;
}
//第三步:给新节点的data数据域指针申请内存
node_new->data = malloc(size);
if(node_new->data == NULL)
{
return node_insert_error4;
}
//第四步:给数据域指针指向内存拷贝数据
memcpy(node_new->data,data,size);//内存拷贝
//第五步:新节点先连接到链表,新节点 的next指向头的next
node_new->next = head->next;
//第六步:头的next指向新的节点
head->next = node_new;
//第七版:插入前的第二节点的前指针指向新节点
node_new->next->prev = node_new;
//第八步:新节点的前指针指向头
node_new->prev = head;
return node_insert_error0;
//第四步:新节点的next指向head的next
//第五步:头节点的next指向新节点.
}
/***********
* 作用:判断链表是否为空
* 函数名: isEmpty
* 参数: head 头指针
* 返回值:如果是空则返回true,否则返回fase
* *************************/
bool isEmpty(node_t* head)
{
if(head == NULL)
{
return true;
}
if(head->next == head)
{
return true;
}
return false;
}
/*************************************
* 函数名:delete_end
* 参 数:head 头节点指针
* 返回值:无
* 作 用:删除双向循环链表最后一个节点
*
**************************************/
void delete_end(node_t* head)
{
//第一步:先判断是否为空
if(isEmpty(head))
{
printf("链表为NULL无法删除\n");
return ;
}
//第二步:定义临时变量保存尾节点
node_t* ptemp = head->prev;
//第三步:尾节点的前一个节点的next指向head
ptemp->prev->next = head;
//第四步:头指针的prev指向temp的前一个指针
head->prev = ptemp->prev;
//第五步:free最后一个节点的data
if(ptemp->data != NULL)
{
free(ptemp->data);
}
//第六步:free最后一个节点
free(ptemp);
ptemp = NULL;
}
void delete_start(node_t* head)
{
if(isEmpty(head))
{
return ;
}
//第一步:保存第一个节点(除头节点外)
node_t* ptemp = head->next;
//第二步:
head->next = ptemp->next;
ptemp->next->prev = head;
if(ptemp->data != NULL)
free(ptemp->data);
free(ptemp);
ptemp = NULL;
}
/*********************************
* 函数名:destroy
* 参 数:head 头节点指针
* 返回值:无
* 作 用:销毁链表(除头节点外全部删除)
*******************************/
void destroyLink(node_t* head)
{
while (!isEmpty(head))
{
delete_end(head);
}
}
void deleteNode(node_t* head,int pos)
{
if(isEmpty(head))
{
return ;
}
node_t* ptemp = head;
int i = 0;
for(i = 0;i < pos && ptemp->next != head;++i)
{
ptemp =ptemp->next;
}
if(i == pos)
{
ptemp->prev->next = ptemp->next;
ptemp->next->prev = ptemp->prev;
free(ptemp->data);
free(ptemp);
ptemp = NULL;
}
}
/**************
* 作用:对某个数据更新
* 参数:node_ptr 需要修改的节点的首地址
* data_updata 修改成什么样子数据的首地址
* pUpdate 函数指针,按照用户自定义进行更新.
*
*
* ********************************/
void node_update(node_t* node_ptr,const void* data_updata,\
void (*pUpdate)(void* a,const void* b))
{
if(node_ptr == NULL || data_updata == NULL|| pUpdate == NULL)
{
return ;
}
pUpdate(node_ptr->data,data_updata);
}
// 写好makefile文件
// 写好main.c的测试文件
// 写好随意位置添加节点(作业)
// 请使用冒泡算法对链表排序 (做不了)
// 把链表打印出来.(暂时不做)
node.h
#ifndef __NODE_H__
#define __NODE_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
void* data; //数据域
struct node* next; //指针域: 指向下一个节点
struct node* prev; //指针域: 指向上一个节点
}node_t,*pnode_t;
enum node_insert_error
{ node_insert_error0 = 0,
node_insert_error1 = 1,//链表头首地址传入错误.
node_insert_error2 = 2,//链表数据节点指针错误
node_insert_error3 = 3, // 传入的位置错误 pos错误 或者pos<0
node_insert_error4 = 4, // 节点申请失败错误.
};
/********
* 函数名:create_node
* 参 数:无
* 返回值:返回链表的首地址
* 功 能:创建一个链表,链表头
*/
node_t* create_node();
/****************************
* 函数名:node_insert_end
* 参数:
* head: 头节点指针
* data:需要插入的数据指针
* size:x需要插入的数据大小
* 返回值:返回错误信息
* 作 用: 在双向链表尾部添加节点
* data 有内存,但没值.
***************************************/
int node_insert_end(node_t* head,void* data,int size);
/****************************
* 函数名:node_insert_start
* 参数:
* head: 头节点指针
* data: 需要插入的数据指针
* size: 需要插入的数据大小
* 返回值:返回错误信息
* 作 用: 在双向链表头部添加节点,在hed节点的下一个节点插入
*
***************************************/
int node_inset_start(node_t* head,void* data,int size);
/*************************************
* 作用:判断链表是否为空
* 函数名: isEmpty
* 参数: head 头指针
* 返回值:如果是空则返回true,否则返回fase
* *************************/
bool isEmpty(node_t* head);
/*************************************
* 函数名:delete_end
* 参 数:head 头节点指针
* 返回值:无
* 作 用:删除双向循环链表最后一个节点
*
******************************/
void delete_end(node_t* head);
/*********************************
* 函数名:destroy
* 参 数:head 头节点指针
* 返回值:无
* 作 用:销毁链表(除头节点外全部删除)
*******************************/
void destroyLink(node_t* head);
/**************
* 作用:对某个数据更新
* 参数:node_ptr 需要修改的节点的首地址
* data_updata 修改成什么样子数据的首地址
* pUpdate 函数指针,按照用户自定义进行更新.
*
*
* ********************************/
void node_update(node_t* node_ptr,const void* data_updata,\
void (*pUpdate)(void* a,const void* b));
void deleteNode(node_t* head,int pos);
#endif
main.c
#include "node.h"
#include "student.h"
int main()
{
node_t* phead = create_node();
if(phead == NULL)
{
printf("链表创建失败\n");
return 0;
}
/*char name[20];
int m_id;
int m_age;
char m_sex:1;
int m_English; //个人的英语成绩*/
stu stu2207[2] = {
{"gongwei", 1,18,0,20},
{"liuzefeng",2,18,1,1}
};
node_inset_start(phead,&stu2207[0],sizeof(stu));
node_inset_start(phead,&stu2207[1],sizeof(stu));
delete_end(phead);
stu tempStu = {"abc",1,2,0,5};
// node_update(node_t* xxxx,&tempStu,student_updata_sex);
}
makefile
OUT : main.o node.o student.o
gcc -g main.o node.o student.o -o OUT
main.o : main.c
gcc -g main.c -o main.o
node.o : node.c
gcc -g node.c -o node.o
student.o : student.c
gcc -g student.c -o student.o
clean:
rm *.o OUT
我写的代码: (六个文件)
day03.h
#ifndef __DAY03_H__
#define __DAY03_H__
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct node
{
void * data; //数据域
struct node* next; //指针域 ,指向下一个节点
struct node* prev; //指针域 ,指向上一个节点
}node_t,*pnode_t;
enum node_insert_error
{
node_insert_error0 = 0, //没错误
node_insert_error1 = 1, //链表的首地址传入错误
node_insert_error2 = 2, //链表的数据节点指针错误
node_insert_error3 = 3, //传入的位置错误
node_insert_error4 = 4, //节点申请失败
};
node_t* create_head_node(); //创建头节点的空间节点
node_t* create_node(); //创建空间节点
int node_insert_end(node_t *head ,void *data ,int size);//尾部添加节点
int node_insert_head(node_t *head ,void *data ,int size);//头部添加节点
void delete_node_head(node_t * head); //删除头部节点
void delete_node_end(node_t * head); //删除尾部节点
int insert_pos_node(node_t *head,int pos,void *data,int size);
void node_update(node_t * ptr,const void *data_updata,void (*pUpdate)(void *a,const void *b ));
void delete_pos_node(node_t* head,int pos);
void delete_some_node(node_t *head);
bool isEmpty(node_t *head);
#endif
day03.c
/************************************************************************************************************************************************************************************************************************
*文件名:day03.c
*作 者:She001
*时 间:
*版 本:
*作 用:双向链表的建立
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include "day03.h"
#include "student.h"
/***************************
* 函数名:create_head_node
* 参数:无
*
*
* 返回值: node_t *s
* 作用:创建头节点的空间节点(x循环列表)
* *************************/
node_t* create_head_node()//创建头节点的空间节点
{
node_t* head = (node_t *)malloc(sizeof(node_t));
if(NULL==head)
{
printf("头节点申请错误!\n");
return NULL;
}
head->data =NULL;
head->next=head;
head->prev=head;
return head;
}
/***************************
* 函数名:create_node
* 参数:无
*
*
* 返回值: node_t *s
* 作用:创建的空间节点
* *************************/
node_t* create_node() //创建空间节点
{
node_t* gw = (node_t *)malloc(sizeof(node_t));
if(NULL==gw)
{
printf("空间申请错误!\n");
return NULL;
}
gw->data=NULL;
gw->next=NULL;
gw->prev=NULL;
return gw;
}
/***************************
* 函数名:node_insert_end
* 参数:node_t *head //头节点
* void *data //数据
* int size //数据大小
*
*
* 返回值: int 类型
* 作用:尾部加入节点(x循环列表)
* *************************/
int node_insert_end(node_t *head ,void *data ,int size)//尾部添加节点
{
if(NULL ==head)
{
printf("首地址错误\n");
return node_insert_error0; //首地址错误
}
if(NULL==data)
{
printf("数据指针错误!\n");
return node_insert_error2; //数据指针错误
}
//申请一个新的节点
node_t* gg=create_node();
if(NULL==gg)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
gg->data=malloc(size);
if(NULL==gg->data)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
memcpy(gg->data,data,size);
head->prev->next=gg;
gg->prev=head->prev;
head->prev=gg;
gg->next=head;
return node_insert_error0;
}
/***************************
* 函数名:node_insert_end
* 参数:node_t *head //头节点
* void *data //数据
* int size //数据大小
*
*
* 返回值: int 类型
* 作用:头部插入空间节点(x循环列表)
* *************************/
int node_insert_head(node_t *head ,void *data ,int size)//头部添加节点
{
if(NULL ==head)
{
printf("首地址错误\n");
return node_insert_error0; //首地址错误
}
if(NULL==data)
{
printf("数据指针错误!\n");
return node_insert_error2; //数据指针错误
}
//申请一个新的节点
node_t* gg=create_node();
if(NULL==gg)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
gg->data=malloc(size);
if(NULL==gg->data)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
memcpy(gg->data,data,size);
gg->next=head->next;
head->next->prev=gg;
head->next=gg;
gg->prev=head;
}
/***************************
* 函数名:isEmpty
* 参数:node_t *head //头节点
*
* 返回值: 无
* 作用:判断链表是否为空
* *************************/
bool isEmpty(node_t *head)
{
if(head==NULL)
{
return true;
}
else if(head->next==head)
{
return true;
}
else
{
return false;
}
}
/***************************
* 函数名:delete_node_end
* 参数:node_t *head //头节点
*
* 返回值: 无
* 作用:删除尾部的空间节点(x循环列表)
* *************************/
void delete_node_end(node_t * head) //删除尾部节点
{
if(isEmpty)
{
return;
}
if(NULL ==head)
{
printf("首地址错误\n");
printf("已经是空的!");
//return node_insert_error1; //首地址错误
return;
}
if((head->prev)==NULL)
{
printf("链表已经为空!\n");
//return node_insert_error1;
return;
}
node_t *p = head->prev;
head->prev=head->prev->prev;
head->prev->prev->next=head;
if(p->data!=NULL)
{
free(p->data);
}
free(p);
p=NULL;
}
/***************************
* 函数名:node_insert_head
* 参数:node_t *head //头节点
*
* 返回值: void
* 作用:删除头部的空间节点(x循环列表)
* *************************/
void delete_node_head(node_t * head) //删除头部节点
{
if(isEmpty)
{
return;
}
if(NULL ==head)
{
printf("首地址错误\n");
printf("已经是空的!");
//return node_insert_error1; //首地址错误
return ;
}
if((head->next)==NULL)
{
printf("链表已经为空!\n");
//return node_insert_error1;
return;
}
node_t *p = head->next;
head->next=p->next;
p->next->prev=head;
if(p->data!=NULL)
{
free(p->data);
}
free(p);
p=NULL;
}
/***************************
* 函数名:delete_some_node
* 参数:node_t *head //头节点
*
* 返回值: void
* 作用:删除除了头部的所有空间节点(x循环列表)
* *************************/
void delete_some_node(node_t *head)
{
if(isEmpty)
{
return;
}
while(head->next!=head)
{
delete_node_head(head);
}
}
/***************************
* 函数名:delete_pos_node
* 参数:node_t *head //头节点
*
* 返回值: void
* 作用:删除固定位置的空间节点(x循环列表)
* *************************/
void delete_pos_node(node_t* head,int pos)
{
if(isEmpty)
{
return;
}
node_t* temp= head;
int i=0;
for(i=0;i<pos&& temp->next !=head;++i)
{
temp=temp->next;
}
if(i==pos)
{
temp->prev->next=temp->next;
temp->next->prev=temp->prev;
if(temp->data!=NULL)
{
free(temp->data);
}
free(temp);
temp=NULL;
}
}
/**********************
* 作用: 对某个数据更新
* 参数: ptr 需要修改数据的首地址
* data_updata 需要更新数据的指针
* pUpdate 函数指针
*
* *******************/
void node_update(node_t * ptr,const void *data_updata,void (*pUpdate)(void *a,const void *b ))
{
if(ptr==NULL || data_updata ==NULL || pUpdate==NULL)
{
return ;
}
pUpdate(ptr->data,data_updata);
}
/***************************
* 函数名:node_insert_end
* 参数:node_t *head //头节点
* void *data //数据
* int size //数据大小
* int pos //数据的位置
*
* 返回值: int 类型
* 作用:插入固定的空间节点(x循环列表)
* *************************/
int insert_pos_node(node_t *head,int pos,void *data,int size)
{
if(NULL ==head)
{
printf("首地址错误\n");
return node_insert_error0; //首地址错误
}
if(NULL==data)
{
printf("数据指针错误!\n");
return node_insert_error2; //数据指针错误
}
//申请一个新的节点
node_t* gg=create_node();
if(NULL==gg)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
gg->data=malloc(size);
if(NULL==gg->data)
{
printf("申请空间的节点失败!\n");
return node_insert_error4;
}
memcpy(gg->data,data,size);
int i=0;
node_t *temp =head;
for(i=0;i<pos&&temp->next!=head;i++)
{
temp=temp->next;
}
if(i==pos)
{
gg->prev=temp->prev;
temp->prev->next=gg;
gg->next=temp;
temp->prev=gg;
}
}
student.h
#ifndef __STUDENT_H__
#define __STUDENT_H__
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include"day03.h"
typedef struct student
{
char name[100];
int m_id;
int m_age;
char sex;
}stu,*pstu;
void student_updata_sex1(void *data1,const void* data2); //接口函数
#endif
student.c
/************************************************************************************************************************************************************************************************************************
*文件名:student.c
*作 者:She001
*时 间:
*版 本:
*作 用:学生的函数
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include "student.h"
#include "day03.h"
void student_updata_sex1(void* data1,const void * data2)
{
pstu ptem1= (pstu)data1;
const pstu ptem2 = (const pstu) data2;
ptem1->sex=ptem2->sex;
}
main.c
/************************************************************************************************************************************************************************************************************************
*文件名:main.c
*作 者:She001
*时 间:
*版 本:
*作 用:程序接口
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include "student.h"
#include "day03.h"
int main()
{
int i;
/*typedef struct student
{
char name[100];
int m_id;
int m_age;
char sex;
}stu,*pstu;*/
stu w={"123",1,1,'0'};
stu w1={"1234",12,12,'1'};
stu w2={"12345",13,13,'2'};
stu w3={"123456",14,14,'3'};
stu w4={"1234567",15,15,'4'};
stu w5={"12345678",16,16,'5'};
node_t* head=create_head_node();
node_insert_head(head ,&w ,sizeof(stu));
node_insert_head(head ,&w1 ,sizeof(stu));
node_insert_head(head ,&w2 ,sizeof(stu));
node_insert_head(head ,&w3 ,sizeof(stu));
node_insert_head(head ,&w4 ,sizeof(stu));
node_insert_head(head ,&w5 ,sizeof(stu));
node_t* temp=head;
for(i=0;temp->next!=head;i++)
{
temp=temp->next;
printf("第%d个学生:\n",i+1);
printf("name:%s \n",((stu*)(temp->data))->name);
printf("id:%d\n",((stu*)(temp->data))->m_id); //temp->data 是一个 void * 因为id 是stu 类型的 所以我们需要一个 stu* 类型的指针来指向
printf("age: %d\n",((stu*)(temp->data))->m_age);
printf("sex: %c\n\n",((stu*)(temp->data))->sex);
}
temp=head->next->next;
node_update(temp,&w,student_updata_sex1);
printf("==========================================================================\n");
temp=head;
for(i=0;temp->next!=head;i++)
{
temp=temp->next;
printf("第%d个学生:\n",i+1);
printf("name:%s \n",((stu*)(temp->data))->name);
printf("id:%d\n",((stu*)(temp->data))->m_id); //temp->data 是一个 void * 因为id 是stu 类型的 所以我们需要一个 stu* 类型的指针来指向
printf("age: %d\n",((stu*)(temp->data))->m_age);
printf("sex: %c\n\n",((stu*)(temp->data))->sex);
}
}
makefile
node : main.o day03.o student.o
gcc -g -o node main.o day03.o student.o
main.o:main.c
gcc -g -c main.c -o main.o
day03.o:day03.c
gcc -g -c day03.c -o day03.o
student.o:student.c
gcc -g -c student.c -o student.o