栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

链表相关知识总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

链表相关知识总结

链表相关知识
目录
  • 前言
  • 链表的定义
  • 链表的分类
  • 单链表的相关操作
  • 链表的优缺点
前言

我们之前使用数组来存放数据,但使用数组时,要先指定数组中包含元素的个数,即数组长度。如果向数组中加入的元素个数超过了数组长度,便不能正确保存其中内容。且这种方式特别浪费空间。这时就希望有一种存储方式,其存储元素的个数是不受限制的,当要添加更多元素时,存储的个数会随之增加,这种方式被称为链表。链表是一种常见的数据结构。

数据的存储结构有两种:

  • 连续存储【数组】
    数组是由固定数目的同类型的元素按顺序排列而构成的数据结构,其中的元素被存储在一段连续的内存空间中
    优点:存取速度很快
    缺点:插入删除元素很慢,空间通常是有限制的,事使用前声明数组长度,需要大块连续的内存块
  • 离散存储【链表】
    链表是一种非连续的数据结构,链表在内存中不连续存储
    优点:空间没有限制 插入删除元素很快
    缺点:存取速度很慢
链表的定义
  • n个结点离散分配
  • 彼此通过指针相连
  • 每个结点只有一个前驱结点,每个节点只有一个后续结点
  • 首节点没有前驱结点,尾节点没有后续结点

专业术语:
首结点:第一个有效节点
尾节点:最后一个有效结点
头节点:第一个有效结点之前的结点,头结点不存放有效数据,且头结点主要为了方便对链表的操作
头指针:指向头结点的指针变量,且存放头结点的地址
尾指针:指向尾节点的指针变量

注:确定一个数组,需要三个参数:元素个数,首地址,长度
如若通过一个函数对链表进行处理,至少需要几个参数?
只需要一个参数:头指针
通过头指针可以推算出链表的其他所有参数(头指针存放头结点的地址,而头结点和其后结点数据类型相同)

定义一个简单的结构体:

struct student 
{
	char name[20];//数据域 
	int age;//数据域 
	struct student * next;//指针域 
};

链表中,一个元素包含两部分:数据域和指针域
数据域:能存放有效数据的地方
指针域:用来指向下一个元素
最后一个元素的指针指向NULL,表示指向地址为空

链表的分类
  • 单链表
  • 双链表
  • 循环链表
  • 非循环链表

单链表:每个结点只有一个指针,每个结点的指针都指向下一结点,所有结点单线联系
双链表:添加了一个指针域,通过两个指针域,分别指向节点的前结点和后节点
循环链表:最后一个结点的指针指向链表头结点,头尾相连,形成一个环形的数据链;

单链表的创建

单链表的建立就是在程序运行的过程中,从无到有的建立一个链表,即一个一个分配结点的内存空间,输入结点的数据,建立结点间的相连关系

头插法:始终让每个新结点放在链表中第一个位置,即对链表进行遍历时先遍历的是最后加入链表的结点
尾插法:每次把新结点放在链表的最后一个位置

int icount;//全局变量表示链表长度 
struct student *create() //定义一个creat函数用来创建链表,函数返回链表的头指针 
{
	struct student *phead=NULL;//初始化链表,头指针为空 
	struct student *pEnd,*pNew; 
	icount=0;//初始化链表长度 
	pEnd=pNew=(struct student *)malloc(sizeof(struct student));
	printf("请输入名字和年龄:n");
	scanf("%s",pNew->name);
	scanf("%d",pNew->age);
	while(pNew->age!=0)
	{
		icount++;
		if(icount==1)
		{
			pNew->next=phead;//使指针指向为空 
			pEnd=pNew;//跟踪新加入的结点 
			phead=pNew;//头指针指向首结点 
		}
		else 
		{
			pNew->next=NULL;//新结点的指针为空 
			pEnd->next=pNew;//原来的结点指向新节点 
			pEnd=pNew;//pEnd指向新结点 
			
		}
		pNew=(struct student *)malloc(sizeof(struct student));//分配新节点的内存空间 
		scanf("%s",&pNew->name);
		scanf("%d",&pNew->age)
	 }
	 free(pNew);//释放结点空间 
	 return phead; 
	
	
	
}
单链表的遍历

将链表创建好后,对链表中的数据进行遍历并进行输出

void print(struct student *phead) 
{在这里插入图片描述


    struct student *pTemp;//定义一个循环所用的临时指针
	int n=1;//链表中的结点序号 
	printf("一共有%d个学生n",icount);
	pTemp=phead;//指针得到首结点的地址 
	while(pTemp!=NULL) 
	{
		printf("第%d个学生是:n",n);
		printf("姓名:%sn",pTemp->name);
		printf("年龄:%dn",pTemp->age);
		pTemp=pTemp->next;//移动临时指针到下一个结点 
		n++;//进行自加运算 
	} 
}
单链表的插入


在1位置插入结点的具体步骤:

  1. 为新建节点申请内存空间和赋值
  2. 定义一个指针指向这个新建结点的地址
  3. 将新建节点插入到首节点和普通结点之间,则新建节点将成为2号位,其后结点位数加一
  4. 将首节点的指针域赋值给新建结点的指针域
  5. 将首节点的指针域指向新建节点

正确写法:
r=p-.>pnext;//r指向p后面的结点
p->pnext=q;//将p的指针域赋给q
q->pnext=r;

struct student * insert(struct student * phead)
{
	struct student *q;//定义q指向新分配的空间
	printf("请输入学生的姓名和年龄: n");
	q=(struct student *)malloc(sizeof(struct student));//分配内存空间
	scanf("%s",&q->name);
	scanf("%s",&q->age);
	q->next=phead;//新结点的指针指向原来的首结点,保存首结点的地址
	phead=pnew;//头指针指向新结点
	icount++;//增加链表的结点数量
	return phead;//返回头指针 
} 
单链表的删除


删除普通结点的步骤:

  1. 首结点的指针域指向普通节点,普通结点的指针域指向尾节点
  2. 将首节点的指针域指向尾节点,相当于删除普通结点
  3. 释放普通节点的内存

正确写法:
r=p->pnext;//指向p后面的结点
p->pnext=r->pnext;//指向p后面的后面的结点
free( r );//释放r的内存

void delete(struct Stu * phead,int n)//phead为头结点,n为要删除的结点序号
{
	int i;
	struct student *pTemp;
	struct student *pPre; 
	pTemp=pHead;
	pPre=pTemp;
	printf("删除第%d个学生  n",n);
	for(i=1;inext;
	}
	pPre->next=pTemp->next;//连接删除结点两边的结点 
	free(pTemp);//释放要删除结点的内存空间 
	icount--;//减少链表中的结点个数 
 } 
链表的优缺点
  • 优点:空间没有限制

  • 优点: 插入删除元素很快

  • 缺点:存取速度很慢

对链表的分享就到这啦,如果有错误,欢迎大家矫正

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/571390.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号