数据结构 day03 基础知识学习 (循环列表)

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 
	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值