单向链表--1链表的增删改查 (C语言版)

前言

在各种信息管理系统的程序设计中,常常需要到大量的数据记录表格,如果采用结构体数组存储这些数据,会出现一些问题。其一是数组必须定义固定的长度,程序运行时数组元素数目也是固定的,若元素数比数组长度长,则会造成越界问题。所以当我们使用结构体数组时,必须尽可能的定义最大数组长度,这样可能会造成内存浪费。其二是在数组中删除与插入元素都需要移动数组中的很多元素,效率很低。
为了更好的解决这些问题,我们可以采用动态存储分配的数据结构——链表。它的特点是用则申请,不用则释放,插入与删除也较为方便。能大大提高空间利用率与时间效率。
在学习链表之前我们来了解一下存储空间的分配和释放

存储空间的分配和释放
C语言标准函数库中提供了四个函数:malloc()、calloc()、realloc()、free(),用来实现内存的动态分配与释放。前三个用来分配内存,第四个用来释放。链表中最常用的是malloc()与free(),下面来简单介绍一下。

  • 申请存储空间函数malloc()
    malloc()函数原型为
    void *malloc(unsigned int size);
    其功能是在内存的动态存储区申请一个长度为size字节的连续存储空间。并返回该存储空间的起始地址。如果没有足够空间可分配,则返回空指针NULL。
  • 释放存储空间函数free()
    free()函数原型为
    void free(void *p);
    其功能是将指针变量p指向的存储空间释放。free函数无返回值。需要说明的是,p只能是程序中此前最后一次调用malloc或calloc函数所返回的地址。

链表的定义

链表是一种最常见的采用动态存储分配方式的数据结构。在链表中,每个元素称为结点。结点通常由数据域与指针域构成。
在这里插入图片描述
数据域存储数据信息,指针域用来连接链表。
如果每个结点只有一个指针域,除了末尾结点指向NULL外其余都指向下一个结点,一个连接一个,称为单向链表或单链表。本次我们主要来讲解一下单链表。在这里插入图片描述

创建链表前的准备工作

创建链表前我们需要定义一个结构体,其中包括数据域与指针域

typedef struct Node
{
	int data;    //数据域
	struct Node *next;   //指针域
}Node;

创建链表

链表分为有头结点链表与无头结点链表
头结点为单链表的第一个元素结点之前设置的一个结点,该结点内不存放数据,只用来指向单链表的第一个元素。对于链表来说,头结点可有可无,但是为了方便操作,通常使用有头结点链表。(本篇使用的是有头结点链表)

Node* CraetList()
{
    Node* head = (Node*)malloc(sizeof(Node));   //为头结点分配内存空间
    if (head == NULL)   //如果没有分配成功
    {
        printf("malloc error!");
        return NULL;
    }
    head->next = NULL;   //初始化头结点的指针
    return head;
}

链表的增加

  • 头插法(在链表第一个元素之前插入一个新元素)
Node *Headadd(Node * head)  //头插法 
{
	int a;
	printf("输入你想添加到链表里的信息个数");
	scanf("%d",&a);   //可以利用头插法插入a个元素
	while(a--)
	{
		Node * n = (Node *)malloc(sizeof(Node));   //为新节点分配内存空间
		int b;
		printf("输入元素信息\n");
		scanf("%d",&b);   //输入你要添加的元素值
		n->data = b;    //将你要输入的值赋给新结点的数据域
		n->next = head->next;   //将新结点的指针指向第一个元素结点
		head->next = n;   //更新head
	}
	return head;
}
  • 尾插法(在链表最后一个元素后添加元素)
Node * InsertListEnd(Node * head,int x)   //尾插法 
{
	Node * n= (Node *)malloc(sizeof(Node));
	n->data=x;
	n->next=NULL;   //初始化指针
	Node * p=head;   //定义一个指针指向head
	while (p->next)   //遍历链表,使p指向最后一个元素
	{
		p=p->next;
	}
	p->next=n;   //将最后一个结点的指针指向新结点
	return head;
}

删除链表中某个结点

删除结点需要找到该结点的前一个元素,令前一个结点的指针指向该结点的后一个结点即可。

Node * DelList(Node * head,int x)  //删除结点(数据域为x的结点)
{
	Node *p=head;   
	int n=0;   //计数器(记录x的出现次数),用于后面判断是否找到值为x的结点
	while(p->next)  //遍历链表,找到数据域为x的结点的前结点
	{
		if(p->next->data == x)
		{
			p->next=p->next->next;  //改变前结点的指向
			n++;  
		}
		else
		p=p->next;
	}
	if(p->data==x)  //判断最后一个结点的值与x是否相等
	{
		p=NULL;
		n++;
	}
	if(n==0)
	printf("未找到该结点");
	return head;
}

修改链表某个结点的值

修改结点的值首先需要找到该结点,再进行修改

Node* Change(Node* head,int a,int b)   //寻找数据为a的结点,将其数据改为b
{
    Node* p = head->next;
    while(p)  //遍历链表寻找数据为a的结点
    {
        if(p->data == a)   
        {
            p->data = b;  //改变结点的值
            break;
        }
        p=p->next;
    }
    return head;
}

链表内结点的查找

寻找元素为x的结点,若找到返回该结点,找不到返回空指针

Node* Find(Node* head,int x)  
{
    Node* p = head->next;
    while(p)
    {
        if(p->data == x)
        return p;
        p=p->next;
    }
    printf("未找到该元素");
    return NULL;
}

打印链表

void Print(Node *head)  //打印 
{
	Node*p=head->next;
	if(p!=NULL)
	{
		printf("%d",p->data);
		p=p->next;
	}
	while(p)
	{
		printf("->%d",p->data);
		p=p->next;
	}
	printf("\n");
	return;
}

小结

  • 此篇博客主要介绍了一些单链表的简单操作,链表在c语言中有着重要的作用,关于链表的其他应用与双向链表会在后期介绍。
  • 以上代码为测试样例,若有错误欢迎指正!!!
  • 部分图片来源于

史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)

单向链表是由若干个节点组成的,每个节点都包含一个数据域和一个指向下一个节点指针域。在单向链表,只能从头节点开始遍历链表,每个节点只能访问其后继节点。下面是用单向链表实现增删改查的代码实现: ```python # 定义单向链表节点类 class ListNode: def __init__(self, val): self.val = val self.next = None # 定义单向链表类 class LinkedList: def __init__(self): self.head = None # 添加节点 def add_node(self, val): new_node = ListNode(val) if not self.head: self.head = new_node else: curr = self.head while curr.next: curr = curr.next curr.next = new_node # 删除节点 def delete_node(self, val): if not self.head: return if self.head.val == val: self.head = self.head.next else: curr = self.head while curr.next: if curr.next.val == val: curr.next = curr.next.next return curr = curr.next # 修改节点 def update_node(self, old_val, new_val): curr = self.head while curr: if curr.val == old_val: curr.val = new_val return curr = curr.next # 查找节点 def search_node(self, val): curr = self.head while curr: if curr.val == val: return True curr = curr.next return False ``` 在上面的代码,我们定义了一个单向链表节点类 ListNode ,包含一个数据域 val 和一个指向下一个节点指针域 next 。然后定义了单向链表类 LinkedList ,包含一个头节点 head 。在 LinkedList ,我们实现了 add_node() 方法用于添加节点,delete_node() 方法用于删除节点,update_node() 方法用于修改节点,search_node() 方法用于查找节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值