单链表详解

一、简介

单链表:是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。(每个结点       只有一个链域的链表称为单链表)

1)链表中的数据是以结点来表示

2)每个结点的构成:元素(数据元素的映象(Node->data)) + 指针(指示后继元素存储位置(Node->next)),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

3)链接方式存储的线性表简称为链表(Linked List)。


链表的具体存储表示为:

1)用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)                 

2)链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))。 

链表的结构:


data域-->存放结点值的数据域 

next域-->存放 存放结点的直接后继的指针域

二、    单链表的多种操作

代码实现:

头文件:list.h

#pragma once
//带头节点的单链表,以NULL结尾

typedef struct Node
{
    int data;
    struct Node*next;
}Node,*List;//List == Node*


//初始化
void InitList(List plist);

//头插,违背生活规律,尽量少用
bool Insert_head(List plist,int val);

//尾插
bool Insert_tail(List plist,int val);

//查找
Node* Search(List plist,int key);

bool Delete(List plist,int key);

int GetLength(List plist);

bool IsEmpty(List plist);

//清空数据
void Clear(List plist);

//销毁链表
void Destroy(List plist);

void Show(List plist);

功能实现:.cpp文件;

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "list.h"
#include <vld.h>

//初始化
void InitList(List plist)
{
	assert(plist != NULL);
	if(plist==NULL)
	{
		return ;
	}

	plist->next = NULL;
}

//头插
bool Insert_head(List plist,int val)
{
	Node *p = (Node *)malloc(sizeof(Node));
	p->data = val;
	p->next = plist->next;
	plist->next = p;
	
	return true;
}

//尾插
bool Insert_tail(List plist,int val)
{
	Node *q;
	for(q=plist;q->next!=NULL;q=q->next);//尾节点q标记为q->next==NULL
	Node *p = (Node *)malloc(sizeof(Node));
	p->data = val;
	p->next = q->next;//p->next = NULL;//将p插在q的后面
	q->next = p;

	return true;
}

//查找
Node* Search(List plist,int key)
{
	for (Node *p = plist->next;p != NULL;p = p->next)
	{
		if (p->data == key)
		{
			return p;
		}
	}
	return NULL;
}
//查找前驱
Node* Precunrsor_Search(List plist,int key)
{
	for (Node *p = plist;p != NULL;p = p->next)
	{
		if (p->next->data == key)
		{
			return p;
		}
	}
	return NULL;
}
bool Delete(List plist,int key)
{
	Node *p = Precunrsor_Search(plist,key);//前驱
	if (p == NULL)
	{
		return false;
	}
	plist = p;
	p = plist->next;
	plist->next = plist->next->next;
	free(p);//注意:由于这里是删除结点,所以要回收内存,free(所选删除的结点),防止内存泄漏。
	p = NULL;//置空以防止出现ye
	return true;


}
int GetLength(List plist)
{
	int count = 0;
	for (Node *p = plist->next;p != NULL; p = p->next)
	{
		count++;
	}
	return count;
}

bool IsEmpty(List plist)
{
	return plist->next == NULL;
}
//清空数据
void Clear(List plist)
{
	Destroy(plist);
}
//销毁链表
void Destroy(List plist)
{
	Node *p;
	while (plist->next != NULL)
	{
		p = plist->next;
		plist->next = p->next;
		free(p);
		p=NULL;
	}

}
//打印函数
void Show(List plist)
{
	for(Node *p=plist->next;p!=NULL;p=p->next)
	{
		printf("%d ",p->data);
	}
	printf("\n");
}
  • 对单链表实现就地逆置(笔试、面试重点)
void Reverse(List plist)
{
    if (plist == NULL || plist->next == NULL || plist->next->next == NULL)
    {
        return ;
    }
    Node *p = plist->next;
    plist ->next = NULL;
    Node *q;
    while (p != NULL)
    {
        q = p->next;
        p->next = plist->next;
        plist->next = p;
        p = q;
        
    }
}
结束语:相比于无头链表,单链表中,增加一个头结点的目的是为了(方便运算的实现),类似于《算法导论》中       讲到的:是作为哨兵的作用,可以使代码简洁方便。而无头链表,没有头结点,则首元素没有前驱结点,在其前插入结点或者删除结点会复杂考虑的多一点。


### 单链表的数据结构详解 单链表是一种常见的线性数据结构,其特点是通过指针接各个节点形成一条路。相比数组,它不需要连续的物理存储空间,因此能够有效突破内存大小对数据量的限制[^1]。 #### 节点定义 在 C 语言中,单链表通常由一个节点组成,每个节点包含两部分:一是用于存储数据的实际字段 `data`;二是指向下一个节点的指针字段 `next`。以下是典型的节点定义: ```c typedef int SLLDataType; typedef struct SLLNode { SLLDataType data; struct SLLNode* next; } Node; ``` 上述代码片段展示了如何定义一个基本的单链表节点类型[^4]。 --- ### 插入操作 插入新节点到特定位置的操作分为以下几个方面考虑: #### 创建节点 为了向单链表中插入新的节点,首先需要动态分配内存并初始化该节点的内容。例如,在 C 中可以通过如下函数创建一个新的节点实例: ```c Node* create_node(SLLDataType value) { Node* new_node = (Node*)malloc(sizeof(Node)); if (new_node != NULL) { new_node->data = value; new_node->next = NULL; } return new_node; } ``` 此函数负责申请一块堆区内的内存区作为新节点,并将其成员变量赋初值。 #### 在指定索引处插入 假设目标是在已知第 k 个位置之前加入某个元素,则需遍历至第 k-1 处找到前驱节点 p_prev 后执行以下步骤: 1. 构造待插的新项 q; 2. 修改原顺序关系使得p_prev→q→(旧k-th item) 成立。 伪码描述如下所示: ```pseudo-code function insert_at_index(head, index, value): newNode ← CreateNewNode(value) IF head IS NULL AND index ==0 THEN RETURN newNode current ← head FOR i FROM 0 TO index -1 DO IF current IS NULL THEN BREAK LOOP ENDIF current ← current.next ENDFOR IF current NOT NULL OR index==0 THEN tempNext ←current.next current.next←newNode newNode.next←tempNext ELSE PRINT ERROR MESSAGE "Invalid Position" ENDIF RETURN head ENDFUNCTION ``` 注意这里仅提供了一个高层次的概念框架而非具体实现版本。 --- ### 删除操作 删除某节点的过程大致相似于查找过程加上额外释放资源的动作。当定位好要移除的目标之后,调整前后连接即可完成任务。不过需要注意边界情况比如首元或者尾端情形特殊处理[^3]。 --- ### 查询与修改 查询即按照给定条件逐一遍历直至满足停止准则为止;而更新则是先寻址再替换相应属性值而已。 --- ### 总结 尽管单链表存在随机访问性能差等缺点,但它依然是学习计算机科学基础不可或缺的一部分[^2]。掌握这些基础知识有助于构建更加复杂的软件解决方案。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值