单链表的基本操作之创建链表并进行简单操作

单链表的创建与基本操作

1、单链表的理解

1.1单链表的定义
	线性表的链式存储又称单链表,它是指通过依据任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向后继的指针。单链表结点如下所示。其中data为数据域,存放数据元素;next为指针域,存放其后继结点的地址。 

在这里插入图片描述

1.2单链表的图形解释

单链表的存储方式

1.1.3单链表的特点

1)单链表不要求逻辑上相邻的两个元素在物理位置上也相邻,因此不需要连续的存储空间。

2)单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。

1.1.4单链表的优点和缺点

优点:

​ 1)在任意位置插入、删除他的时间复杂度为O(1)。

​ 2) 没有增容问题,插入一个开辟一个空间 ,不会对开辟的空间资源浪费。

缺点:

1) 单链表的数据是链式存储的,它的元素是不支持随机访问的 ,所以它的时间复杂度为O(n)。

2) 每存放一个元素时需要另外开辟一个指针域的空间,使得多次调用。

2.1、单链表的创建代码

typedef struct LNode		//定义单链表节点类型
{
	ElemType data;			//定义节点存放一个数据元素
	struct LNode* next;		//指针指向下一个节点
}LNode,*LinkList;
2.2代码的实现
2.2.1主函数 main.cpp
#include"LinkList.h"

void test1()
{
	LinkList L;
	InitList(L);
int main()
{
	test1();
	return 0;
}
2.2.2 函数的实现
#include"LinkList.h"

//初始化一个单链表(带头节点)
Status InitList(LinkList& L)
{
	L = (LNode*)malloc(sizeof(LNode));	//创建头节点
	if (L == NULL)	//内存不足分配失败
		return flase;
	L->next = NULL;		//只有一个头节点,下一个节点应该置空
	return true;
}

//判断单链表是否为空
Status Empty(LinkList L)
{
	if (L->next == NULL)
		return true;
	return flase;
}

//使用头插建立单链表,n表示要插入的个数
Status CreateList_front(LinkList& L, int n)
{
	L = (LNode*)malloc(sizeof(LNode));	//创建头节点
	if (L == NULL)
		return flase;
	L->next = NULL;		//头节点的next域置为空
	int i;
	ElemType x;		//后续要输入的值,存放入x中
	for (i = 0; i < n; i++)
	{
		LNode* newNode = (LNode*)malloc(sizeof(LNode));		//新建节点
		if (newNode == NULL)
			return flase;
		cout << "请输入x的值:";
		cin >> x;					//输入数据
		newNode->data = x;			//存放数据
		newNode->next = L->next;	//将节点插在首节点之间,头节点之后
		L->next = newNode;
	}
}

//使用尾插建立单链表,n表示要插入的个数
Status CreateList_tail(LinkList& L, int n)
{
	LinkList s;
	L = (LNode*)malloc(sizeof(LNode));		//新建头节点
	if (L == NULL)
		return flase;
	L->next = NULL;
	s = L;		//用来指向链表的尾节点
	int i;
	ElemType x;
	for (i = 0; i < n; i++)
	{
		LNode* newNode = (LNode*)malloc(sizeof(LNode));		//创建节点
		if (newNode == NULL)
			return flase;
		cout << "请输入x的值:";
		cin >> x;
		newNode->data = x;
		newNode->next = s->next;		//将节点插入尾节点之后
		s->next = newNode;
		s = newNode;
	}
	s->next = NULL;		//尾节点的next域置NULL
}

//按位查找,查找第 i 个位置的值,并用 e 返回
ElemType LocateElem(LinkList L, int i, ElemType& e)
{
	LNode* p;		//p指向头节点
	p = L->next;
	int j=1;
	while (p&&j!=i)		//寻找下标为i的节点p
	{
		p = p->next;
		j++;
	}
	if (j < i)		//查找的i小于链表的长度
		return flase;
	e = p->data;
	return e;		//找到并返回e
}

//按值查找,查找第一个值等于 e 的下标并返回
Status Locate_e(LinkList L, ElemType e)
{
	LNode* p;		//p指向头节点
	p = L->next;		
	int i = 1;
	while (p && p->data != e)		//查找值为e的节点p
	{
		p = p->next;
		i++;
	}
	if (p == NULL)		//为找到
		return flase;
	return i;		//找到了,返回i
}
	
//删除第 i 个位置的值,并用 e 返回
Status DelElem(LinkList& L, int i, ElemType& e)
{
	LinkList p, pre;		//建立指向头节点的p,和指向节点p前驱的pre
	p = L->next;
	pre = L;
	int j=1;
	while (p && j != i)		//寻找第i位的节点p
	{
		pre = p;
		p = p->next;
		j++;
	}
	if (j < i)		//未找到
		return flase;
	e = p->data;			//找到并释放p指针,并用e存放p指向的值
	pre->next = p->next;
	free(p);
	p = NULL;
	return true;
}

//删除第一个值等于 e 的值,并用下标返回 e 出现的位置
Status Del_e(LinkList& L, ElemType e)
{
	LNode* p, *pre;		//建立指向头节点的p,和指向节点p前驱的pre
	p = L->next;
	pre = L;
	int i = 1;
	while (p && p->data != e)		//查找值为e的节点
	{
		pre = p;
		p = p->next;
		i++;
	}
	if (p==NULL)		//循环结束还没找到时
		return flase;
	pre->next = p->next;		//找到后释放p指针
	free(p);
	p = NULL;
	return i;	//返回找到值的下标
}

//依次打印单链表的值
Status LinkList_print(LinkList L)
{
	LNode* p;
	p = L->next;
	cout << "单链表的值为:";
	while (p)
	{
		cout << "  "<<p->data;
		p = p->next;
	}
	if (p != NULL)
		return flase;
	return true;
}

//在第 i 个位置后插入值e
Status Insert_e(LinkList& L, int i, ElemType e)
{
	LNode* p;		//建立指向头节点的p
	p = L->next;
	int j = 1;
	ElemType x;
	while (p && j != i)		//寻找第i位的节点p
	{
		p = p->next;
		j++;
	}
	if (j < i)		//未找到
		return flase;
	LNode* newNode = (LNode*)malloc(sizeof(LNode));		//创建节点
	if (newNode == NULL)
		return flase;
	cout << "请输入x的值:";
	cin >> x;
	newNode->data = x;
	newNode->next = p->next;	//将新建节点插入i之后
	p->next = newNode;
}

2.2.3 函数的声明
#pragma once
#include<iostream>
#include<stdlib.h>
using namespace std;

#define flase -1
#define ture 1;

typedef int ElemType;
typedef int Status;

typedef struct LNode		//定义单链表节点类型
{
	ElemType data;			//定义节点存放一个数据元素
	struct LNode* next;		//指针指向下一个节点
}LNode,*LinkList;

//初始化一个单链表(带头节点)
Status InitList(LinkList& L);

//判断单链表是否为空
Status Empty(LinkList L);

//使用头插建立单链表,n表示要插入的个数
Status CreateList_front(LinkList& L, int n);

//依次打印单链表的值
Status LinkList_print(LinkList L);

//使用尾插建立单链表,n表示要插入的个数
Status CreateList_tail(LinkList& L, int n);

//按位查找,查找第 i 个位置的值,并用 e 返回
ElemType LocateElem(LinkList L, int i, ElemType& e);

//按值查找,查找第一个值等于 e 的下标并返回
Status Locate_e(LinkList L, ElemType e);

//删除第 i 个位置的值,并用 e 返回
Status DelElem(LinkList &L, int i, ElemType& e);

//删除第一个值等于 e 的值,并用下标返回 e 出现的位置
Status Del_e(LinkList &L, ElemType e);

//在第 i 个位置后插入值e
Status Insert_e(LinkList& L, int i, ElemType e);

3、代码的部分功能运行截图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skaEu4Hw-1651591499834)(D:\博客\单链表\3.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aj6zpnRq-1651591499837)(D:\博客\单链表\4.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BpTZjMQl-1651591499838)(D:\博客\单链表\5.png)]

4、总结

​ 曾经老师和我们说过,敲代码的三个境界就是:看代码是代码,看代码是内存,看代码就是代码。

我觉得这境界的体现就在学习单链表中能够更好的体现出来。单链表是 一组地址任意的存储单元存放线性表中的数据元素 ,你既要想象出数据的存储,还有理解下一个数据的存放地址。

``

3、代码的部分功能运行截图

运行截图
运行截图运行截图

4、总结

​ 曾经老师和我们说过,敲代码的三个境界就是:看代码是代码,看代码是内存,看代码就是代码。

我觉得这境界的体现就在学习单链表中能够更好的体现出来。单链表是 一组地址任意的存储单元存放线性表中的数据元素 ,你既要想象出数据的存储,还有理解下一个数据的存放地址。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值