数据结构之链表的相关功能实现

思维导图

链表的相关操作作业:

1】 按值修改

2】按值查找,返回当前节点的地址 (先不考虑重复,如果有重复,返回第一个)

3】 逆置(反转)

4】释放链表

link_list.h代码:

#ifndef __LINK_LIST_H__
#define __LINK_LIST_H__
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node//节点的结构体定义
{
	union//将头节点和普通节点的数据域放在一起定义
	{
		int length;//头节点的数据域
    	datatype data;//普通节点的数据域
	};
    struct node *next;//指针域:指向下一个节点的首地址
}node,*node_p;
node_p create_link_list();//创建单链表
int empty_link_list(node_p N);//单链表的判空
node_p create_node(int data);//创建普通节点
void insert_head(node_p N,datatype data);//头插
void show_link_list(node_p N);//遍历输出链表
void insert_tail(node_p N,datatype data);//尾插
void insert_pos(node_p N,int pos,datatype data);//按任意位置将节点插入链表
void delete_head(node_p N);//头删
void delete_tail(node_p N);//尾删
void delete_pos(node_p N,int pos);//按任意位置删除链表中的节点
void mod_pos_node(node_p N,int pos,datatype mod_data);//按位置修改链表中的节点
void mod_data_node(node_p N,int find_data,datatype mod_data);//按值修改链表中的节点
node_p find_data_node(node_p N,int find_data);//按值查找链表中的节点,查找到之后返回当前节点的地址
void inverse(node_p N);//链表节点的逆置
void free_link_list(node_p *N);//释放链表
#endif

link_list.c代码:

#include "link_list.h"
//创建单链表(实际上是创建头节点)
node_p create_link_list()
{
	//从堆区申请空间存放链表
	node_p Node=(node_p)malloc(sizeof(node));
	if(NULL == Node)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	Node->length=0;//刚创建链表时,里面没有节点,节点长度为0
	Node->next=NULL;//链表中没有节点,头节点指向空
	printf("链表创建成功!\n");
	return Node;
}
//单链表的判空
int empty_link_list(node_p N)
{
	if(NULL == N)
	{
		printf("链表创建不合法!\n");
		return -1;
	}
	return N->length==0?1:0;
}
//创建普通节点
node_p create_node(datatype data)
{
	//在堆区申请空间创建节点
	node_p new =(node_p)malloc(sizeof(node));
	if(new == NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	new->data=data;//存数据到普通节点数据域
	new->next=NULL;//将定义的新的普通节点指针域置空
	return new;
}
//将普通节点插入到链表头部(头插)
void insert_head(node_p N,datatype data)
{
	if(NULL == N)
	{
		printf("插入链表失败!\n");
		return;
	}
	node_p n=create_node(data);
	n->next=N->next;
	N->next=n;
	N->length++;
}
//遍历输出链表
void show_link_list(node_p N)
{
	if(NULL == N || empty_link_list(N))
	{
		printf("链表不合法!\n");
		return;
	}
	node_p q=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<N->length;i++)
	{
		q=q->next;//指针指向第一个节点
		printf("%d ",q->data);//输出节点数据域的数据
	}
	putchar(10);
}
//将普通节点插入到链表尾部(尾插)
void insert_tail(node_p N,datatype data)
{
	if(NULL == N)
	{
		printf("链表不合法!\n");
		return;
	}
	node_p q=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	node_p new=create_node(data);//定义一个用于接收创建的新节点的指针
	//寻找最后一个节点的方法一:
	/*
	for(int i=0;i<N->length;i++)
	{
		q=q->next;
		if(q->next == NULL)
		{
			q->next=new;//将尾插的前一个节点指针域指向当前的新节点
		}
	}
	*/
	//寻找最后一个节点的方法二:
	while(q->next!=NULL)
	{
		q=q->next;
	}
	new->next=NULL;//将尾插的新节点指针域指向NULL
	q->next=new;//将尾插的前一个节点指针域指向当前的新节点
	N->length++;//链表长度自增
}
//按任意位置将节点插入链表
void insert_pos(node_p N,int pos,datatype data)
{
	if(NULL == N || pos <=0 || pos >N->length+1)
	{
		printf("链表插入节点失败!\n");
		return;
	}
	node_p q=N;
	node_p new=create_node(data);
	for(int i=0;i<pos-1;i++)
	{
		q=q->next;//寻找你要插入第几个位置节点的前一个节点
	}
	new->next=q->next;//类似于头插的操作,将新插入该位置节点的指针域指向下一个节点
	q->next=new;//将新插入该位置节点的前一个节点的指针域指向该新插入的节点
	N->length++;//链表长度自增
}
//头删
void delete_head(node_p N)
{
	if(NULL ==N || empty_link_list(N))
	{
		printf("删除链表头节点失败!\n");
		return;
	}
	node_p p=N->next;//定义一个指针接收要删除的第一个节点的地址指向
	N->next=N->next->next;//N->next=p->next;//将头节点的指针域指向第二个节点
	N->length--;//链表长度自减
	free(p);//释放第一个节点的空间
	p=NULL;//避免野指针
}
//尾删
void delete_tail(node_p N)
{
	if(NULL ==N || empty_link_list(N))
	{
		printf("删除链表尾节点失败!\n");
		return;
	}
	node_p p=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<N->length-1;i++)
	{
		p=p->next;//找到最后一个节点的前一个节点指针p
	}
	node_p q=p->next;//找到最后一个节点指针q
	p->next=q->next;//p->next=p->next->next;将最后一个节点的指针域的指向赋给最后一个节点的前一个节点的指针域
	free(q);//释放删除的节点指针
	q=NULL;//把释放的节点指针置空,防止野指针
	N->length--;//链表长度自减
}
//按位置删除链表中的节点
void delete_pos(node_p N,int pos)
{
	if(NULL ==N || empty_link_list(N) || pos <=0 ||pos >N->length)
	{
		printf("按位置删除节点失败!\n");
		return;
	}
	node_p p=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<pos-1;i++)
	{
		p=p->next;//找到删除节点的前一个节点指针p
	}
	node_p q=p->next;//找到要删除的节点指针q
	p->next=q->next;//p->next=p->next->next;将最后一个节点的指针域的指向赋给最后一个节点的前一个节点的指针域
	free(q);//释放删除的节点指针
	q=NULL;//把释放的节点指针置空,防止野指针
	N->length--;//链表长度自减
}
//按位置修改链表中的节点
void mod_pos_node(node_p N,int pos,datatype mod_data)
{
	if(NULL ==N || empty_link_list(N) || pos <=0 ||pos >N->length)
	{
		printf("修改节点失败!\n");
		return;
	}
	node_p p=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<pos;i++)
	{
		p=p->next;
	}
	if(p->data == mod_data)
	{
		printf("值相同,不需要做修改操作!\n");
		return;
	}
	p->data=mod_data;//修改当前节点的数据域
}
//按值修改链表中的节点
void mod_data_node(node_p N,int find_data,datatype mod_data)
{
	if(NULL ==N || empty_link_list(N))
	{
		printf("修改节点失败!\n");
		return;
	}
	if(find_data == mod_data)
	{
		printf("数据值相同,不需要修改!\n");
	}
	node_p p=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<N->length;i++)
	{
		p=p->next;
		if(p->data == find_data)
		{
			p->data=mod_data;//修改当前节点的数据域
			return;
		}
	}
}
//按值查找链表中的节点,查找到之后返回当前节点的地址
node_p find_data_node(node_p N,int find_data)
{
	if(NULL ==N || empty_link_list(N))
	{
		printf("查找节点失败!\n");
		return NULL;
	}
	node_p p=N;//定义一个用于遍历的指针,存放和头节点指向相同的地址
	for(int i=0;i<N->length;i++)//遍历链表的所有节点
	{
		p=p->next;
		if(p->data == find_data)
		{
			return p;//按值查找,找到后返回当前节点的地址
		}
	}
}
//逆置(反转)
void inverse(node_p N)
{
	if(NULL ==N || empty_link_list(N))
	{
		printf("逆置操作失败!\n");
		return;
	}
	if(N->length == 1)
	{
		printf("此链表中只有一个节点,无需逆置!\n");
		return;
	}
	node_p p=N->next->next;//让指针p指向第一个要头插节点
	N->next->next=NULL;//将第一个节点的指针域置空,让它变成最后一个节点
	node_p q;//定义指针q用于存放第一个要头插节点的下一个节点指针
	while(p!=NULL)
	{
		q=p->next;//让指针q指向指针p的下一个节点
		p->next=N->next;//头插操作
		N->next=p;
		p=q;//头插完第一个要头插的节点之后,将下一个节点的指针再传给p,继续让它当头插节点
	}
}
//释放链表
void free_link_list(node_p N)
{
	if(NULL == N)
	{
		printf("链表不合法,无需释放!\n");
		return;
	}
    while(H->next!=NULL)
    {
        delete_tail(N);//把头节点后面的节点全部删掉释放
    }
	free(N);
	N=NULL;
}

main.c代码:

#include "link_list.h"
int main(int argc, const char *argv[])
{
	node_p N=create_link_list();//定义一个结构体指针接收申请的单向链表头节点的地址(N即为头指针)
	insert_head(N,10);
	insert_head(N,20);
	insert_head(N,30);
	insert_head(N,40);
	insert_head(N,50);
	insert_head(N,60);
	insert_head(N,70);
	show_link_list(N);
	insert_tail(N,9);
	insert_tail(N,8);
	insert_tail(N,7);
	show_link_list(N);
	insert_pos(N,3,55);
	insert_pos(N,5,45);
	show_link_list(N);
	delete_head(N);
	show_link_list(N);
	delete_tail(N);
	show_link_list(N);
	delete_tail(N);
	show_link_list(N);
	delete_pos(N,3);
	show_link_list(N);
	delete_pos(N,2);
	show_link_list(N);
	mod_pos_node(N,4,37);
	show_link_list(N);
	mod_pos_node(N,6,12);
	show_link_list(N);
	mod_data_node(N,40,42);
	show_link_list(N);
	node_p a=find_data_node(N,9);
	printf("%p\n",a);
	inverse(N);
	show_link_list(N);
	free_link_list(N);
    N=NULL;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值