链表基础知识总结

本文详细介绍了链表的定义,包括它的非连续存储和通过指针链接的特性。链表由结点组成,每个结点包含数据域和指针域。文章还讨论了头结点的作用,如简化处理和统一空表与非空表的管理。此外,列举了链表的基本操作,如初始化、销毁、置为空、求长度、获取元素、插入和删除元素,并提供了相应的代码示例。同时,介绍了单链表的创建方法,包括头插法和尾插法。
摘要由CSDN通过智能技术生成

什么是链表

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点都包括两部分:一是数据域,用来存储元素数值数据,另一个是存储直接后继结点地址的指针域,该指针一般称为next,用来指向下一个结点的位置。由于下一个结点也是链表类型,所以next的指针也要定义为链表类型。

链表概念及特点

头指针:是指向链表中第一个结点的指针
首元结点:是指链表中存储的第一个数据元素的结点
头结点:是在链表的首元结点之前附设的一个结点
在这里插入图片描述
在链表中设置头结点有何好处?

1、便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其他位置一致,无须进行特殊处理
2、便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。

头结点的数据域内装的是什么?

可以为空,也可以存放线性表的长度等附加信息,但此节点不能计入链表长度值

链表的特点:

1、结点在存储器中的位置是任意的,即逻辑相邻的数据元素在物理上不一定相邻
2、访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间是不同的

单链表的表示

typedef struct Lnode{  //声明结点的类型和指向结点的指针类型
	ElemType data;	//数据域
	struct Lnode *next;		//指针域
}Lnode,*LinkList; 	//LinkList为指向结构体Lnode的指针类型

单链表的基本操作

单链表的初始化

bool InitList_L(LinkList& L) {
	L = new Lnode;
	L->next = NULL;
	return true;
}

单链表的销毁

bool DestoryedList_L(LinkList &L){
	LinkList p; // Lnode *p;
	While(p){
		p = L;
		L = L -> next;
		delete p;
	}
	return true;
}

将单链表置为空表

bool clearList_L(LinkList &L){
	Lnode *p,*q;
	p = L->next;	// 首元结点
	While(p){	// 未到表尾
		q = p->next;
		delete p;
		p = q;	// p指针后移
	}	// 直到p,q指针指向均为空
	L -> next = NULL;	// 头结点指针域为空
	return true;
} 

求单链表的表长

从首元结点开始,依次统计所有节点

int ListLength_L(LinkList &L){
	Lnode *p;
	int i = 0;
	P = L -> next;
	while(p){
		i++;
		p = p->next;
	}
	return i;
}

取单链表中第i个元素的内容

从链表的头指针出发,顺着链域next逐个节点往下搜索,直至搜索到第i个结点为止。因此,链表不是随机存取结构

bool getElem_L(LinkList &L,int i,ElemType &e){
	Lnode *p;
	p = L->next;  //初始化
	int j = 1;
	while(i > j && p) { //向后扫描,直到p指向第i个元素或者p为空
		j++;
		p = p -> next;
	} 
	if(!p || j > i){  //第i个元素不存在
		return 0;
	}
	e = p -> data;  //取第i个元素
	return true;
}

查找

根据指定数据获取该数据所在的位置
1、从第一个结点开始,依次和e相比较
2、如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址
3、如果查找整个链表都没有找到其值与e相等的元素,则返回0或Null
查找返回地址

Lnode *LocateElem_L(LinkList &L,Elemtype e){
	p = L -> next;
	while(p && p -> data != e){
		p = p -> next;
	}
	return p;
}

查找返回值

// 在线性表L中查找值为e的数据元素的位置序号
int LocateElem_L(LinkList &L,Elemtype e){
	p = L -> next;
	int j = 1;
	while(p && p -> data != e){
		j++;
		p = p -> next;
	}
	if(p){
		return j;
	}
	return 0;
}

插入节点

1、首先找到ai-1的存储位置p
2、生成一个数据域为e的新结点s
3、插入新结点:
(1)新结点的指针域指向ai;
(2)结点ai-1的指针域指向新结点e
在这里插入图片描述
① S -> next = p -> next;
② P -> next = s;
注:①②顺序不可直接交换,否则会造成ai地址丢失

bool ListInsert_L(LinkList &L,int i,Elemtype e){
	Lnode *p;
	p = L;
	int j = 0;
	while(p && j < i - 1){
		p = p -> next;
		j++;
	}
	if(!p || j > i - 1){  // i大于表长+1或者小于1,插入位置非法
		return false;
	}
	s = new Lnode;	// 生成新结点s
	s -> data = e;  // 将结点s的数据域置为e
	s -> next = p -> next;	// 将s插入L中
	p -> next = s;
	return true;
}

删除结点

1、首先找到ai-1的存储位置p,保存要删除的ai的值
2、令p -> next 指向 ai + 1
3、释放结点ai的空间

bool destoryedList_L(LinkList &L, int i,Elemtype &e){
	Lnode *p;
	p = L;
	int j = 0;
	while(p && j < i - 1){ //寻找第i个结点并令p指向其前驱
		p = p -> next;
		j++;
	}
	if(!p || j > i - 1){
		return false;
	}
	Lnode *q ;
	q = p -> next; //临时保存被删结点的地址以备释放 	
	p -> next = q->next;   //改变删除结点前驱的指针域
	e = q -> data; 		// 保存被删除结点的数据域
	//p -> next = (p -> next)->next;
	delete q;  // 释放删除节点的空间
	return true;
}

建立单链表

1.头插法/前插法:

1、从一个空表开始,重复读入数据
2、生成新结点,将读入数据存放到新结点的数据域中
3、从最后一个结点开始,依次将各结点插入到链表的前端
在这里插入图片描述

void CreateList_H(LinkList &L,int n){
	L = new Lnode;
	L -> next = NULL; 	//先建立一个带头结点的单链表
	for(int i = n ;i > 0; i--){
		p = new Lnode; //生成新结点
		cin >> p -> data; // 输入元素值
		p -> next = L -> next; // 插入到表头
		L -> next = p;
	}
}
2.尾插法/后插法:
void CreateList_L(LinkList &L,int n){
	L = new Lnode;
	L -> next = NULL;
	r = L ;  //尾指针r指向头结点
	for(int i = 0;i < n;i++){
		p = new Lnode;
		cin >> p -> data;
		p -> next = NULL;  
		r -> next = p; //插入到表尾
		r = p;  //r指向新的尾结点
	}
}

  • 25
    点赞
  • 202
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值