链表是顺序表的升级版,它的存储空间是不连续,因此在进行删除,插入操作的时候,不需要像顺序表一样把后面的所有元素进行前移覆盖,因此更加方便,下面我们首先用代码来创建一个链表。
一个结构体的节点由它存储的内容以及一个指向下一个结点的指针组成,可以把整个链表理解为一个打了很多结的绳子,一个节点由一个绳结和两段绳结之间的绳子组成,绳结就是数据域,即存储的数据内容,中间的绳子就是指针,连接两个不同的节点。
一.创建一个节点
typedef struct LNODE{
void* data;//定义一个空指针,因为还没有明确定义数据的类型
struct LNODE* next; /*这个就是指向下一个节点的指针
由于它指向的类型就是struct LNODE,因此这样命名*/
}LNODE,*LINK_NODE; /*这是两个别名,LNODE是struct LNODE的别名,
LINK_NODE是其指针,即struct LNODE*的别名*/
这样一个节点就创建好了。
二.创建完整的链表
typedef struct {
int size;//链表的长度
LINK_NODE nodes;//一个指向struct NODE 的指针,用于申请相应的内存来存储链表中的每个节点
}LINKED_LIST
以后我们在每次要定义一个链表的时候就只需要去直接使用LINKED_LIST就好了,比如:LINKED_LIST list1;就完成了一次定义。
三.对结点和链表进行初始化
我们写两个函数来为结点分配内存,为链表分配内存
LINK_NODE initNODE(LINK_NODE next,int datasize,const void*indata){
(LINK_NODE)newnode=(LINK_NODE)malloc(sizeof(LNODE));//给节点分配内存
newnode->data=malloc(datasize+1);/*由于我们的数据现在还是一个空指针,
因此我们直接这样申请,防止字符串的问题因此我们+1*/
memset(newnode->data,0,datasize+1);//将数据初始化为零
memcpy(newnode->data,indata,datasize);//相当于提前把所有需要的数据整合在了indata这个数组里面,
传入这个数组,把indata拷贝到newnode结构体里面的data数组里面
newnode->next=next;//给节点之中的指针赋值
return newnode;
}
总结一下,对于节点,
第一步是用一个新的结构体指针申请内存,这是针对节点整体而言的;
第二步是把节点里面的每一个内容进行赋值,
第一,对指针,传一个外部的指针;
第二,对里面的数据内容而言,通过指针的方式可以适应不同的数据类型,先申请一段内存,再去将外部传入的内容拷贝到相应的内存里面,memset,memcpy函数是对内存进行拷贝,适应的数据类型也更多。
LINKED_LIST initLINKED_LIST(){
LINKED_LIST* newlist=(LINKED_LIST*)malloc(sizeof(LINKED_LIST));//给链表进行内存分配
newlist->size=0;//先将链表的长度定义为零
newlist->nodes=initNODE(NULL,0,NULL);//创建一个虚拟头节点
return newlist;
}
总结一下,对于链表,
第一步还是为链表申请内存;
第二步还是针对链表里面的各项内容分别进行赋值;
首先是对长度进行初始化,第二是对里面所谓的“结构体数组”(是不连续的内存)进行首地址的初始化。