链表

/*****************************************************
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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值