[数据结构] [C语言] 线性表的链式表示和实现——单链表

线性链表

线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这些存储单元可以是连续的,也可以不连续)。

因此为了表示每个数据元素与其后继元素之间的逻辑关系,对于数据元素来说,除了储存其本身的信息之外,还需储存一个指示其直接后继的信息(即直接后继的存储位置)。这两部分组成数据元素的存储映像,称为结点(node)。

结点包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指针域。指针域中存储的信息称作指针或链。

n个结点链结成一个链表,即为线性表(a1, a2, ... ,an)的链式存储结构。又由于此链表中每个结点中只包含一个指针域,故又称为线性链表单链表

单链表

gloab.h
#ifndef GLOBAL_H
#define GLOBAL_H
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define OK 1             // 通过
#define ERROR 0          // 错误
#define OVERFLOW -2      // 堆栈上溢
#define UNDERFLOW -3     // 堆栈下溢
typedef int Status;      // 函数类型,其值为状态码
typedef int ElemType;    // 抽象数据类型

#endif // !GLOBAL_H
存储结构
// 线性表的单链表存储结构
typedef struct LNode
{
	ElemType data;
	struct LNode* next;
}LNode, * LinkList;
获取元素
Status GetElem_L(LinkList L, int i, ElemType* e)
{
	// L为带头结点的单链表的头指针
	// 当第i个元素存在时,其值赋给*e并返回OK,否则ERROR
	LinkList p = L->next; // 初始化,p指向第一个结点
	int j = 1; // 计数器
	while (p && j < i) {
		p = p->next;
		++j;
	}
	if (!p || j > i) // 第i个元素不存在
		return ERROR;
	*e = p->data; // 第i个元素
	return OK;
}
插入元素
Status ListInsert_L(LinkList L, int i, ElemType e)
{
	// 在带头结点的单链线性表L中第i个位置之前插入元素e
	LinkList p = L;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		++j; // 寻找第i-1个结点
	}

	if (!p || j > i - 1)
		return ERROR; // i小于1或者大于表长加1

	LinkList s = (LinkList)malloc(sizeof(LNode)); // 生成新结点
	s->data = e;
	s->next = p->next; // 插入L中
	p->next = s;

	return OK;
}
删除元素
Status ListDelete_L(LinkList L, int i, ElemType* e)
{
	// 在带头结点的单链线性表L中,删除第i个元素,用*e返回
	LinkList p = L;
	int j = 0;
	while (p->next && j < i - 1) {
		p = p->next; // 寻找第i个结点,并令p指向其前驱
		++j;
	}
	if (!(p->next) || j > i - 1) {
		return ERROR; // 删除位置不合理
	}
	LinkList q = p->next;
	p->next = q->next;
	if (e) *e = q->data;
	free(q); // 删除并释放结点
	return OK;
}
创建链表
LinkList CreateList_L(LinkList L, int n)
{
	// 逆序位输入n个元素的值,建立带表头结点的单链线性表L
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;	// 先建立一个带头结点的单链表
	for (int i = n; i > 0; --i) {
		LinkList p = (LinkList)malloc(sizeof(LNode)); // 生成新结点
		scanf("%d", &p->data); // 输入元素的值
		p->next = L->next;
		L->next = p; // 插入到表头
	}
	return L;
}
遍历
Status ListTraverse_L(LinkList L, Status(*visit)(ElemType))
{
	LinkList p = L->next;
	while (p) {
		if (visit(p->data)) {
			p = p->next;
		}
		else {
			return ERROR;
		}
	}
	return OK;
}

测试
int main() {
	LinkList L = CreateList_L(NULL, 5);
	printf("\n创建后为:");
	ListTraverse_L(L, PrintElement);
	ListInsert_L(L, 3, 7);
	printf("\n插入后为:");
	ListTraverse_L(L, PrintElement);
	ListDelete_L(L, 3, NULL);
	printf("\n删除后为:");
	ListTraverse_L(L, PrintElement);
}

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值