前言
头节点:链表的第一个节点,该节点的数据域一般不存放数据
首元节点:头节点后边的第一个节点
头指针:指向第一个元素所在的节点
单链表中可以没有头结点,但是不能没有头指针!
实现功能
- 有头节点的空链表的创建
- 指定位置插入节点
- 按大小顺序插入节点
- 删除下标为i的节点
- 删除某个节点
- 查询链表是否为空
- 打印链表
- 销毁链表
程序源码
/*有头节点的单链表*/
#include <stdio.h>
#include <stdlib.h>
/*类型重定义,方便以后修改变量类型*/
typedef int datatype;
typedef struct node_st
{
datatype data; //数据域
struct node_st *next; //指针域
}list;
/*函数声明*/
list *list_create(); //创建只有头节点的空链表
int list_insert_at(list *head, int i,datatype *data); //指定位置插入
int list_order_insert(list *head,datatype *data); //按顺序插入
int list_delete_at(list *head,int i,datatype *data); //删除下标为i的元素
int list_delete(list *head,datatype *data); //删除某个元素
int list_isempty(list *head); //检查链表是否为空
void list_display(list *head); //打印链表
void list_destroy(list *head); //销毁链表
int main()
{
int i = 0,sz,ret;
datatype arr[] = {4,3,2,1,0};
list *head; //定义头指针
sz = sizeof(arr)/sizeof(*arr); //数组元素个数
head = list_create(); //创建空链表,返回头指针
if(head == NULL) //创建失败则退出程序
{
exit(1);
}
printf("链表的插入\n");
for(i=0;i<sz;i++)
{
// ret = list_insert_at(head,0,&arr[i]); //按指定位置插入元素
ret = list_order_insert(head,&arr[i]); //按顺序插入元素
if(ret != 0)
{
exit(1);
}
}
list_display(head); //打印链表
printf("删除某个节点\n");
int value1 = 2;
list_delete(head,&value1); //删除某个元素
list_display(head);
printf("删除i位置的节点\n");
datatype value2,err;
err = list_delete_at(head,0,&value2);//删除0号节点
if(err)
{
exit(1);
}
list_display(head);
printf("delte:%d\n",value2); //被删除节点的值
list_destroy(head); //销毁链表
return 0;
}
/*函数定义*/
//创建只有头节点的空链表
list *list_create()
{
list *head; //定义结构体指针变量
head = malloc(sizeof(*head)); //申请内存空间,大小为list结构体
if(head == NULL) //申请内存失败
{
return NULL;
}
head->next = NULL; //头节点的指针域设为空,数据域不管
return head; //返回空链表的结构体指针(头指针)
}
//指定位置插入
int list_insert_at(list *head, int i,datatype *data)
{
//计数方式:不包括头节点,第一个有效节点从0开始
int j = 0;
list *p = head; //使用p代替head进行后面操作
list *q;
if(i < 0) //下标有误,i要>=0
{
return -1;
}
//找i-1位置的原因:单向链表只能往一个方向遍历,
//若p指针指向的是i位置的节点,那么就无法知道i位置的前驱是哪个节点
//若p指针指向的是i-1位置的节点,就可以知道i位置的前驱就是i-1节点的后继
/*寻找i位置的前驱节点*/
while(j<i && p->next!=NULL)//从第1个有效节点开始,寻找i-1位置,当i=0时,首部插入
{
p = p->next; //p指向下一个节点
j++;
}
if(p) //p不为空指针
{
q = malloc(sizeof(*q));//为新节点申请内存空间
if(q == NULL)
{
return -2;
}
q->data = *data; //新节点的数据域
//q->next = NULL; //指针域暂时为空
q->next = p->next; //p,q的指针域指向同一个后继节点
p->next = q; //使q成为p的后继节点
return 0;
}
else //找不到
{
return -3;
}
}
/*按升序插入元素*/
int list_order_insert(list *head,datatype *data) //按顺序插入
{
list *p = head,*q;
/*寻找数据域>=*data的前驱节点*/
//p->next为空时,说明空链表或p指向尾节点
//p->next->data < *data:p节点的下一个节点的数据域小于*data
while(p->next && p->next->data < *data)
{
p = p->next; //结构体指针p指向下一个节点
}
q = malloc(sizeof(*q)); //为新节点申请内存空间
if(q==NULL) //申请内存失败
{
return -1;
}
// 原先: 1 2 p 5
//插入后:1 2 p q 5
q->data = *data; //新节点q的数据域存放*data
q->next = p->next; //将节点p的指针域赋值给q的指针域,此时p和q的指针域都指向了同一节点
p->next = q; //将节点p的指针域指向q,此时p的指针域指向了q,所以q成为p的后继节点
return 0;
}
//删除下标为i的元素,*data为删除的节点的数据
int list_delete_at(list *head,int i,datatype *data)
{
int j = 0;
list *p = head,*q;
if(i<0) //下标有误,i>=0
{
return -1;
}
/*寻找i-1处的节点*/
//p->next==NULL时,p指向了空链表或p指向了尾节点
while(j<i && p->next)
{
p = p->next;
j++;
}
if(p->next) //p不是尾节点(空链表)
{
//要删除q节点:q的前驱指向q的后继,跳过q
q = p->next; //使p成为q的前驱节点
p->next = q->next;//q的前驱指向q的后继
*data = q->data; //返回要删除的数值
free(q);
q = NULL;
return 0;
}
else
{
return -2;
}
}
//删除某个元素
int list_delete(list *head,datatype *data)
{
list *p = head,*q;
/*寻找数据域是*data的前驱节点*/
while(p->next && p->next->data != *data)
{
p = p->next;
}
if(p->next == NULL)//链表为空或p是尾节点,没找到
{
return -1;
}
else //找到了,删除q节点
{
q = p->next; //使p成为q的前驱节点
p->next = q->next; //q的前驱节点指向q的后继节点
free(q); //释放内存空间
q = NULL;
}
}
//链表是否为空
int list_isempty(list *head)
{
if(head->next==NULL)
return 0;
return 1; //不为空
}
//打印链表
void list_display(list *head)
{
list *node = head->next;//第1个有效节点,头节点的数据域不用
if(list_isempty(head)==0)
return ;
while(node != NULL)
{
printf("%d ",node->data);
node = node->next;
}
printf("\n");
return ;
}
//销毁链表
void list_destroy(list *head)
{
list *node,*next_node;
for(node=head->next;node!=NULL;node=next_node)
{
next_node = node->next;
free(node); //销毁有效节点
}
free(head); //销毁头节点
return ;
}