返回值
返回所申请的头结点所在的内存空间首地址
,即创建单向链表的头结点,代码如下:node_t *create_link_node_1(){
node_t *phead = (node_t *)malloc(sizeof(node_t));
if(NULL == phead){
printf("内存分配失败\n");
exit(-1);
}
//或者memset(phead, 0, sizeof(node_t));
phead->data = -1;
phead->next = NULL;
return phead;
}
内存分配是否成功
;shell命令exit(-1)退出
;每个结点都有数据域和指针域
,而头结点的数据域可以不储存任何数据
,头结点的数据域
在此函数中,被赋值 -1
;指针域被赋值 NULL
,表示此时的单向链表只有一个头结点
;地址传参
的方式创建单向链表的头结点,代码如下:int create_link_node_2(node_t **phead,int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
*phead = (node_t *)malloc(sizeof(node_t));
if(NULL == *phead){
printf("内存分配失败\n");
return -1;
}
//或者memset(*phead, 0, sizeof(node_t));
(*phead)->data = data;
(*phead)->next = NULL;
return 0;
}
二级指针变量
,因为二级指针用来存储一级指针变量的地址
,即所申请的单向链表头结点在内存空间的地址
;入参合理性检查
;内存分配是否成功
;数据域被赋值 -1
;指针域被赋值 NULL
;头结点和第0个结点之间
插入新结点,即头插法
,代码如下:int insert_link_list_1(node_t *phead,int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
//创建新结点
node_t *pnew = NULL;
create_link_node_2(&pnew,data);
//头插到链表
pnew->next = phead->next;
phead->next = pnew;
return 0;
}
pnew
;pnew->next = phead->next
;phead->next = pnew
;最后一个结点后面插入新结点
,即尾插法
,代码如下:int insert_link_list_2(node_t *phead,int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
//创建新结点
node_t *pnew = NULL;
create_link_node_2(&pnew,data);
//遍历链表,找到最后一个结点
node_t *ptemp = phead;
while(NULL != ptemp->next){
ptemp = ptemp->next;
}
ptemp->next = pnew;
return 0;
}
pnew
;ptemp
;ptemp->next = pnew
;int insert_link_list_3(node_t *phead,int pos,int data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(pos < 0){
printf("插入位置不合理,插入失败\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
if(NULL == ptemp){
break;
}
ptemp = ptemp->next;
}
if(i < pos){
printf("插入位置不合理,插入失败\n");
return -1;
}
node_t *pnew = NULL;
create_link_node_2(&pnew,data);
pnew->next = ptemp->next;
ptemp->next = pnew;
return 0;
}
ptemp
;pnew
;pnew->next = ptemp->next
;ptemp->next = pnew
;头删法
,代码如下:int delete_link_list_1(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表只有一个头结点,无其他的结点\n");
return -1;
}
node_t *pdel = phead->next;
phead->next = pdel->next;
free(pdel);
pdel = NULL;
return 0;
}
pdel
,并将头结点的指针域指向待删结点的地址,即node_t *pdel = phead->next
;phead->next = pdel->next
;free(pdel)
;pdel = NULL
;尾删法
,代码如下:int delete_link_list_2(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表只有一个头结点,无其他的结点\n");
return -1;
}
//遍历链表,找到倒数第二个结点
node_t *ptemp = phead;
while(NULL != ptemp->next->next){
ptemp = ptemp->next;
}
free(ptemp->next);
ptemp->next = NULL;
return 0;
}
while循环
,遍历单向链表,找到倒数第二个结点
,即ptemp
;释放ptemp的指针域,并赋值NULL
,这样就删除了链表的最后一个结点;指定结点在链表中的位置,然后根据位置,删除待删结点
,代码如下:
示例代码:
int delete_link_list_3(node_t *phead,int pos){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表只有一个头结点,无其他的结点\n");
return -1;
}
if(pos < 0){
printf("删除位置不合理,删除失败\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
break;
}
}
if(i < pos){
printf("删除位置不合理,删除失败\n");
return -1;
}
node_t *pdel = ptemp->next;
ptemp->next = pdel->next;
free(pdel);
pdel = NULL;
return 0;
}
ptemp
;node_t *pdel = ptemp->next
;ptemp->next = pdel->next
;free(pdel)
;pdel = NULL
;位置查找数据
,代码如下:int search_link_list(node_t *phead,int pos,int *data){
if(NULL == phead || NULL == data){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表只有一个头结点,无其他的结点\n");
return -1;
}
if(pos < 0){
printf("查找位置不合理\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
break;
}
}
if(i < pos){
printf("查找位置不合理,查找失败\n");
return -1;
}
*data = ptemp->next->data;
return 0;
}
ptemp
;取*后的形参指针data
,即 *data = ptemp->next->data
;位置修改数据
,代码如下:int modify_link_list(node_t *phead,int pos,int new_data){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
if(NULL == phead->next){
printf("链表只有一个头结点,无其他的结点\n");
return -1;
}
if(pos < 0){
printf("修改位置不合理\n");
return -1;
}
node_t *ptemp = phead;
int i = 0;
for(i = 0; i < pos; i++){
ptemp = ptemp->next;
if(NULL == ptemp->next){
break;
}
}
if(i < pos){
printf("修改位置不合理,修改失败\n");
return -1;
}
ptemp->next->data = new_data;
return 0;
}
ptemp
;ptemp->next->data = new_data
;清空除了头结点之外的所有结点的数据域和指针域
,区别于顺序表的清空
,代码如下:int clean_link_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL\n");
return -1;
}
node_t *ptemp = phead;
node_t *pdel = NULL;
while(ptemp->next != NULL){
pdel = ptemp->next;
ptemp->next = pdel->next;
free(pdel);
pdel = NULL;
}
return 0;
}
新结点ptemp
,并将头结点的地址赋值给新结点的地址,即备份头结点
,防止头结点被删除
;待删结点pdel
,赋初值为空指针
;while循环
,借助头删法
,除头结点外,删除剩余结点
;包含单向链表的头结点在内
,销毁
单向链表的所有结点
,代码如下:int destroy_link_list(node_t **phead){
if(NULL == phead || NULL == *phead){
printf("入参为NULL\n");
return -1;
}
clean_link_list(*phead);
free(*phead);
*phead = NULL;
return 0;
}
清空单向链表
,是为了防止单向链表直接销毁后,导致内存空间泄漏
的情况产生;释放头结点所占用的内存空间
,并赋值NULL
;第0个数据结点
后面的所有数据结点
,依次头插
到头结点和第0个数据结点之间
即可,代码如下:int filp_link_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL,请检查..\n");
return -1;
}
if(NULL == phead->next){
printf("只有一个头结点\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个数据结点\n");
return -1;
}
node_t *p = phead->next;
node_t *q = p->next;
node_t *ptemp = NULL;
p->next = NULL;
while(NULL != q){
ptemp = q->next;
q->next = phead->next;
phead->next = q;
q = ptemp;
}
return 0;
}
第0个数据结点指针
,并将头结点的指针域指向第0个结点
的指针,即node_t *p = phead->next
;第1个数据结点指针
,并把第0个数据结点的指针域指向第1个数据节点的指针
,即node_t *q = p->next
;保存指针q的指针域
,即ptemp = q->next
,以便于循环遍历单向链表的所有数据结点
,即每次循环结束前,令q = ptemp,就可以继续向后遍历其他的数据结点
;头插法
的形式,并利用while循环
,将第1个数据结点
及其以后的所有
数据结点依次头插到头结点和第0个数据结点之间
,直到指针q为NULL
,即原单向链表
的第0个结点的指针域为NULL
,就完成了单向链表的所有数据结点的翻转
;冒泡排序
,即可完成单向链表所有数据结点的排序
,代码如下:nt sort_link_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL,请检查..\n");
return -1;
}
if(NULL == phead->next){
printf("只有一个头结点\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个数据结点\n");
return -1;
}
node_t *p = phead->next;
node_t *q = NULL;
int temp = 0;
while(NULL != p->next){
q = p->next;
while(NULL != q){
if(p->data > q->data){
temp = p->data;
p->data = q->data;
q->data = temp;
}
q = q->next;
}
p = p->next;
}
return 0;
}
头结点的指针域指向p
,即 node_t *p = phead->next
;其他的结点指针域指向q
,用于循环中,即 q = p->next
;第一层循环
结束的条件是NULL != p->next
;第二层循环
结束的条件是NULL != q
;比较指针p和指针q的数据域
,不符合
if条件语句内条件,就交换
,然后指针p不动,向后移动指针q
,符合
if条件语句内条件,指针p不动,向后移动指针q,直到指针q为NULL
,最后最大值
就是指针p指向的结点数据域
,即p->data
;去除单向链表中重复的数据结点
,代码如下:int del_rep_link_list(node_t *phead){
if(NULL == phead){
printf("入参为NULL,请检查..\n");
return -1;
}
if(NULL == phead->next){
printf("只有一个头结点\n");
return -1;
}
if(NULL == phead->next->next){
printf("只有一个数据结点\n");
return -1;
}
node_t *p = phead->next;
node_t *q = NULL;
node_t *k = NULL;
while(NULL != p){
k = p;
q = p->next;
while(NULL != q){
if(p->data != q->data){
k = k->next;
q = q->next;
} else {
//删除结点q
k->next = q->next;
free(q);
//q = NULL;
//也可直接让q后面的那个结点的地址覆盖q的地址
q = k->next;
}
}
p = p->next;
}
return 0;
}
头结点的指针域指向p
,此时的p
就是第0个结点的地址
;q = p->next
;始终用来保存q前面的那个结点的地址
,也可以备份指针p
,即 k = p
;while循环
,比较p和q的数据域
,若不等
,就向后移动指针k和q
,若相等
,就删除q指向的结点
,直到q=NULL
;while循环
,遍历整个单向链表,直到p=NULL;