数据结构复习 ---- 链表(一)

一、链表相关的定义

  • 什么是链表

链表是为了表示每个数据元素ai与其直接后继元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息被称为指针或者链。这两部分信息组成数据元素ai的存储映像,称为节点(Node)。
n个节点(ai的存储映像)链接成一个链表,即为线性表(a1,a2,…,an)的链式存储结构,因为此链表的每个节点中只包含一个指针域,所以叫单链表。

  • 链表的重要组成
    头指针:链表中第一个结点或头结点的存储位置叫做头指针;它具有标识作用,常用头指针冠以链表的名字;无论链表是否为空,头指针均不为空,它是链表的必要元素;
    头结点:单链表第一个结点前设置的一个结点叫做头结点(为了方便操作),其数据域一般无意义,也可以存放链表的长度;其不一定是链表的必要元素;

二、链表的代码描述

1.节点结构定义

typedef struct LinkList {
	ElemType data;				//数据域,ElemType指代数据类型
	struct LinkList* next;		//指针域
}Node;

2.链表的读取

思路:声明一个指针p,使其指向链表的第一个节点,然后while循环使得p一直往下一个节点走,直到i == index时或者p为空时,退出循环;此时判断p是否为空,如果为空说明p已经走完了整个链表,那么说明该链表不存在index所指节点,index超出了链表的范围或者链表的节点数;否则的话,说明p不为空并且i == index,那么说明成功找到了该节点,将p->data返回给*data;

参数:
	Node &list	[in] 已存在链表的引用
	int index	[in] 需要读取的数据位置索引
	int *data	[inout] 返回读取的值
	
void GetData(Node &list, int index, int *data) {
	Node* p;
	int i = 1;
	p = list.next;
	while(p && i < index) {
		p = p->next;
		++i;
	}
	if(!p || i > index) {
		cout << "不存在该节点!" << endl;
		return; 
	} 
	*data = p->data;
	cout << "链表中第"  << index << "个元素的值为:" << *data << endl; 
}

3.链表的插入和删除

思路:插入的标准语句:newNode->next = p->next; p->next = newNode;p为你想插入的位置的前一个位置,你所需要的就是讲p与它后面一个节点的链接断开,所以你需要让插入的新节点先与后一个节点链接上,然后在让p把新的接点连接上,这样就算插入成功了;至于怎么找到这个位置,和读取时候一样遍历链表;

参数:
	Node &list	[in] 已存在链表的引用
	int index	[in] 需要插入的数据位置索引
	int *data	[in] 需插入的数据
	
void ListInsert(Node& list, int index, int data) {
	int i = 1;
	Node* newNode,*p;
	p = &list;
	while(p && i < index) {
		p = p->next;
		++i;
	}
	if(!p || i > index) {
		cout << "不存在第" << index << "个位置!" <<endl;
		return; 
	}
	newNode = (Node*)malloc(sizeof(Node));
	newNode->data = data;
	newNode->next = p->next;
	p->next = newNode;
	cout << "成功在链表中第"  << index << "个位置插入:" << data << endl;
}

思路:删除节点的标准语句,p->next = delNode->next;free(delNode); 先让p->next接手delNode的下一个节点,然后再将delNode的数据按需要返回,再将其申请的内存释放;如何找到该节点也与读取操作遍历链表方式一样;

参数:
	Node &list	[in] 已存在链表的引用
	int index	[in] 需要删除的数据位置索引
	int *data	[inout] 返回需删除的数据
	
void ListDelete(Node& list, int index, int *data) {
	Node* p,*delNode;
	p = &list;
	int i = 1;
	while(p && i < index) {
		p = p->next;
		++i;
	}
	if(!p || i > index) {
		cout << "不存在第" << index << "个位置!" <<endl;
		return; 
	}
	delNode = p->next;
	*data = delNode->data;
	p->next = delNode->next;
	delNode->next = NULL;
	cout << "成功删除链表中第"  << index << "个元素:" << *data << endl;
}

4.链表的整表创建

思路:用头插法方式构建链表,就是将构建的新节点依次插入头结点之后,newNode->next = list.next;list.next = newNode;
srand((unsigned)time(NULL));初始化随机数种子;
data = rand() % 100;data取100以内的随机数;

参数:
	Node &list	[in] 已存在链表的引用
	int data	[in] 新创建节点的数据
	
void InsertByHead(Node& list, int data) {
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = data;
	newNode->next = list.next;
	list.next = newNode;
}

参数:
	Node &list	[in] 已存在链表的引用
	int len		[in] 创建链表的长度
	
void CreateList(Node& list, int len) {
	int data;
	srand((unsigned)time(NULL));
	for(int i = 0; i < len; ++i) {
		data = rand() % 100;
		InsertByHead(list, data);
	}
	cout << "成功创建长度为 " << len << " 的链表!" << endl; 
}

5.链表的整表删除

思路:循环遍历链表,只要当遍历到的节点不为空时,就销毁该节点,直到只剩一个头结点,将其指针域置空;

参数:
	Node &list	[in] 欲删除的链表
	
void ClearList(Node& list) {
	Node* p,*temp;
	p = list.next;
	while(p) {
		temp = p->next;
		free(p);
		p = temp;
	} 
	list.next = NULL;
	cout << "成功销毁链表!" << endl;
} 

三、测试代码

#include<iostream>
#include<cstdlib>
#include<ctime>

using namespace std;

int main() {
	Node list;
	list.next = NULL;
	CreateList(list, 10);	//创建长度为10的链表
	int data;
	GetData(list, 5, &data); 	//取第五个节点的数据
	ListInsert(list, 6, 1234); 	//在第六个位置插入1234
	ListDelete(list, 9, &data);	//删除第九个节点并返回其数据
	
	//遍历链表
	Node* p = list.next;
	while(p) {
		cout << p->data << endl;
		p = p->next; 
	} 
	
	ClearList(list);	//销毁链表
	
	getchar();
	return 0;
}

在这里插入图片描述

四、总结

链表确实是数据结构比较重要也比较基础的部分,而且链表还有循环链表、静态链表、双向链表几种。学好链表的目的是为了更好的掌握链式存储结构,更好的理解指针,理解数据在内存中是什么样的存在,各种数据之间是怎么关联起来的。这对后面学习像树啊图啊这样比较复杂比较丰富的数据结构时,会很有帮助。
总结一些经验,对比链表这种链式存储结构和数组等一些顺序存储结构,其优势在于插入和删除比较方便,不影响其他的节点数据,但是也因为他不是一种连续的存储形式,在查找时需要遍历,所以选择使用哪种数据结构也要根据实际需要来权衡选择。没有最优的数据结构,只有最合适的数据结构。

发布了15 篇原创文章 · 获赞 5 · 访问量 1271

猜你喜欢

转载自blog.csdn.net/weixin_44816732/article/details/104075666