/*****************************************************
copyright (C), 2014-2015, Lighting Studio. Co., Ltd.
File name:
Author:Jerey_Jobs Version:0.1 Date:
Description:
Funcion List:
*****************************************************/
#include <stdio.h>
#include <stdlib.h> //用于malloc
#include <time.h>
struct node //定义结构体
{
int num;
/* char name[20];
char sex;
int age;
char addr[200];
int tel;*/
struct node * next; //指针域,指向下一个指针,名字为next,指针类型是自己的类型node
};
typedef struct node Node; //把结构体类型(struct node)再取名为Node,方便下面的调取
typedef Node * Link; //相当于typedef struct node * Link; 指针类型 struct node * 再取名为Link
void create_link(Link * head) //链表函数创建,实参和型参同名,好操作,因为是二级指针,所以要带*
{
*head = NULL; //链表没有结点,是空的,没有确切的地址
}
void display(Link head) //display函数,一级指针
{
Link p; //头指针不能移动,所以要另外创建一个p
p = head;
if(NULL == head) //看是不是空链表
{
printf("Link is empty!\n");
return;
}
while(NULL != p) //只要不指向空,尾结点是空 有判断的,常量放前面,有错误的话编译会报错 这里的p不能是p->next,当p已经指向尾结点的时候,已经是NULL,下面就不输出
{
printf("%d\n",p->num); //只要不是空就输出,p指向结点的值域输出
p = p->next; //输出完以后,指针域指向下一个结点指向p
}
}
void is_malloc_ok(Link new_node) //错误处理函数,
{
if(NULL == new_node) //返回值错误是NULL
{
printf("malloc error!\n");
exit(-1); //退出
}
}
void create_node(Link * new_node) //创建新的结点,二级指针
{
*new_node = (Link) malloc(sizeof(Node)); //Link是强制类型转换
is_malloc_ok(*new_node); //有可能内存分配失败,进行错误处理
}
void insert_node_head(Link *head,Link new_node) //插入到头结点,头指正是二级指针,要修改返回,就一定是二级指针,第二个是一级指针
{
new_node->next = *head; //新的指针域指向原来的头 成员运算符有 -> 和 . 如果是成员运算符的指针,用->,如果是成员运算符的变量,用 .
*head = new_node; //头指针指向新的结点
}
void release_link(Link * head) //释放链表,
{
Link p;
p = *head; //函数参数是二级,所以head要一级
while(NULL != p) //不是NULL就释放
{
*head = (*head)->next; //括号不能丢,成员运算符比*要高
free(p);
p = *head; //头指向NULL,即完成释放
}
}
void insert_node_tail(Link * head,Link new_node) //尾插
{
Link p;
p = *head;
if(NULL == *head) //链表为空,不存在尾结点,头指针为空,插入的是唯一的结点,即是头结点也是尾结点,不仅要修改头指针,还要插入
{
*head = new_node; //改变头指针
new_node->next = NULL; //NULL即是头结点也是尾结点
}
else
{
while(NULL != p->next) //链表不为空,寻找尾巴插入 这里是p->next和display不一样,p=NULL指向了尾结点后面,找不到
{
p = p->next; //p指向尾结点
}
p->next = new_node; //新的结点作为新的尾巴,原来的尾巴变成倒数第二个
new_node->next = NULL;
}
}
void insert_node_mid_front(Link * head,Link new_node,int loc) //中间插入(结点的前面)
{
Link p,q; //这俩个参数要一块动
p = q = *head; //都指向头
if(NULL == *head) //如果链表为空
{
*head = new_node;
new_node->next = NULL;
}
else if((*head)->num == loc) //结点的位置就是我要找的值
{
new_node->next = *head; //这两个位置不能倒,新的结点的指针域指向原来的头,头指针指向新的结点
*head = new_node;
}
else
{
// while(p->num != loc && p != NULL) //如果输入20,会出现段错误 ,&&是短路运算符,因为如果前面错误,后面就不会进行
while(p != NULL && p->num != loc)
{
q = p;
p = p->next;
}
// if(NULL == p) //因为NULL退出循环
// {
// q->next = new_node; //插到尾巴上
// new_node->next = NULL;
// }
// else //p不等于NULL,找到了位置
// {
q->next = new_node;
new_node->next = p;
// }
}
}
void insert_node_mid_sort(Link * head, Link new_node) //一边插入一边排序
{
Link p,q;
p = q = *head;
if(NULL == *head) //如果链表是空的,即是头又是尾
{
*head = new_node;
new_node->next = NULL;
}
else if((*head)->num > new_node->num) //头结点的值大于新的结点的值
{
new_node->next = *head;
*head = new_node;
}
else
{
while(p != NULL && p->num < new_node->num)
{
q = p;
p = p->next;
}
q->next = new_node;
new_node->next = p;
}
}
void delete_node(Link * head,int num_del) //删除
{
Link p, q;
p = q = *head;
if(NULL == *head) //空的没什么好删除的
{
printf("Link is empty!\n");
return;
}
else if((*head)->num == num_del) //头结点就是我要删除的值
{
*head = (*head)->next ;
free(p);
return;
}
else
{
while(NULL != p && p->num != num_del)
{
q = p;
p = p->next;
}
if(NULL == p) //没有这个结点
{
printf("no such node!\n");
}
else //删除
{
q->next = p->next;
free(p);
}
}
}
Link search_node(Link head,int num_serch) //查找,要返回,不能void
{
Link p;
p = head;
if(NULL == head)
{
printf("Link is empty!\n");
return NULL;
}
else
{
while( p != NULL && p->num != num_serch)
{
p = p->next;
}
if(NULL == p)
{
return NULL;
}
else
{
return p;
}
}
}
int main()
{
Link head = NULL; /*相当于struct node * head; 指向结构体类型的指针,取名为head,就是头结点
指向 NULL,否则就可能成为野指针 */
Link new_node = NULL; //创建新的结点,用于插入,指向新的结点
int i;
int loc; //用于插哪的变量
int num_del; //用于删除
int num_serch; //用于查找
Link p_serch;
create_link(&head); //创建链表,找到头指针就能找到全部,希望返回的是地址,是二级指针,即指针变量的地址,在上面创建函数
srand((unsigned)time(NULL));
for(i = 0; i < 10;i++) //用于插入结点的循环
{
// new_node = (Link)malloc(sizeof(Node));
create_node(&new_node);
// new_node->num = i + 1; //用于给值域赋值,检查是否创建成功
new_node->num = rand() % 100; //随机数
//scanf("%d",&new_node->num); //与上上面的比较,这需要一个个输入
//insert_node_head(&head,new_node);
//insert_node_tail(&head,new_node); //链表尾插,NULL的时候可能修改头指针,所有head要二级指针
insert_node_mid_sort(&head,new_node); //一边插入一边排序,由小到大
}
display(head); //显示(编译)链表,这是一级指针,一级指针修改的是内容,二级指针修改的是地址,在上面编写display函数
#if 0
printf("\n\n");
create_node(&new_node); //再创建一个新的结点
new_node->num = 100; //给结点赋值,也可以scanf输入,用于插入到前面
printf("please input loc:\n");
scanf("%d",&loc); //用于插入的位置
insert_node_mid_front(&head,new_node,loc); //中间插入(结点的前面),因为是单向链表,只能指向后面,不能指向前面需要两个参数,一个结点位置,一个前面的位置
//中间插入(结点的后面),让新的结点指向p后面的结点,即p->next,再让p->next指向新的结点
display(head);
printf("please input num to delete:\n"); //删除的输入
scanf("%d",&num_del);
printf("\n\n");
delete_node(&head,num_del);
display(head);
#endif
printf("please input num to search:\n"); //输入查找
scanf("%d",&num_serch);
p_serch = search_node(head,num_serch); //查找
if(NULL == p_serch)
{
printf("no such node!\n");
}
else
{
printf("%d\n",p_serch->num);
}
release_link(&head); //释放链表,避免内存泄露,但是并没有指向NULL,还是指向原来没有释放的原来位置,所以要指向NULL,修改了头指针的指向,所以要二级指针
display(head); //看是否释放了
return 0;
}
链表
最新推荐文章于 2023-01-01 14:24:44 发布