《算法笔记》读书记录DAY_26

本文介绍了链表作为数据结构的基础概念,包括链表的内存分配、创建、查找、插入和删除元素的操作。通过示例详细阐述了如何使用C++的new和delete关键字管理链表节点的内存,并提及了C++ STL中的链表容器list。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CHAPTER_7  提高篇(1)——数据结构(1)

 7.3.1链表的概念

线性表是一种很常用的数据结构,它是n个相同特性的元素组成的序列,分为顺序表和链表。其中顺序表我们可以简单地理解成“数组”的概念,它是一块连续的地址来存储给定长度的表结构。而链表则是由若干个结点组成(每个结点代表一个元素),它们在内存中并不是连续在一起存储的,因此每个结点内含有一个指针指向下一个元素。

我们可以用结构体表示链表:

struct node {
	type date;     //type表示元素的类型,例如int或者char 
	node* next;
};

每一个结点都有一个指针next,指向下一个结点的位置,这样就像串链子一样形成一个线性结构。需要注意的是,第一个结点通常不存放数据,我们将其称作头结点(head),它标志着一个链表的开始。同样地,最后一个结点的指针next的值为空,它标志着链表的结束。

 

 7.3.2为链表结点分配内存空间

上一节我们已经了解了链表结点的定义,这节我们介绍如何在每次使用新结点时分配相应的内存  空间。关于内存的申请和释放,我们使用C++的new和delete关键字。

new运算符

new是用来申请动态空间的运算符,其返回类型是申请的同变量类型的指针,其基本用法如下:

typename* p=new typename;

例如申请一个int型变量和一个node型变量:

int* p=new int;
node* p=new node;

有一点要注意,申请空间有可能失败,当失败时会启动C++异常机制处理,在没有特殊处理的情况下会退出程序。不过,一般正常分配一个结点空间,是不会失败的。

delete运算符

delete运算符与new成对使用,当我们用指针p申请了一个对应的空间,在使用完毕后切记使用delete将空间释放,否则容易产生内存泄露。

node* p=new node;
delete(p);        //释放内存

 7.3.3链表的基本操作

链表的创建

我们已经能够创建零散的结点了,接下来要做的是把这些结点连接成链表。方法也很简单,用for循环来把每个结点的next指向下一个即可。例如下面存储int型数据的链表。

typedef struct Node {
	int date;
	node *next;
}node;

node* create(int array[],int n) {     //array为需要加入链表的数据,n为数据个数  
	node *p, *pre, *head;             //pre记录当前结点的前一个结点,head为头结点
	head=new node;
	head->next=NULL;                  //头结点的指针域初始化为空 
	pre=head;                         //前驱结点初始化为第一个结点
	for(int i=0;i<n;i++) {
		p=new node;                   //新建一个结点
		p->data=array[i];             //赋值 
		p->next=NULL;                 //指针域设为空,在下面的步骤中将其放在链表最后面
		pre->next=p;                  //将p连接之最后 
		pre=p;                        //pre记录最后一个结点的前一个 
	}
	return head;
}

查找元素

我们如何在链表中查找是否有某元素x呢?其实也很简单,我们设立一个计数器count并将其初始化为0,然后从头结点开始遍历链表,依次判断当前结点的date是否等于x,如果相等则令count++。

int search(node* head,int x) {
	int count=0;
	node *p=head->next;        //从第一个结点开始
	while(p) {
		if(p->data==x)
			count++;
		p=p->next;
	} 
	return count;
}

插入元素

我们先明确链表插入的定义:我们在链表的第i个位置x,是指在不包括头结点的情况下,插入完成后使第i个元素成为x。例如1 2 3 4,我们要在第3个位置插入5,那么插入结果为1 2 5 3 4。

我们要在第i个位置插入结点p,要找到第i个位置的前一个结点pre,例如要在第1个位置插入要找到头结点,在第3个位置插入要找到第二个结点(头结点不计入)的位置。找到前一个结点pre后,用临时指针tmp存储pre->next,然后令pre->next=p,p->next=tmp,这样就完成了结点的插入。如下图

void insert(node* head,int pos,int x) {
	node *p=new node, *pre=head, *tmp;
	p->data=x;
	for(int i=0;i<pos-1;i++) {          //找到插入位置的前一个结点 
		pre=pre->next;               
	}
	tmp=pre->next;
	pre->next=p;
	p->next=tmp;
}

删除元素

对链表来说,删除元素x是指删除链表上所有值为x的结点。删除结点与插入类似,需要一个pre指针来指向欲删除结点p的前一个结点,令pre->next=p->next,delete(p)即可。

void del(node* head, int x) {
	node *p=head->next, *pre;
	while(p) {                  //从头结点后一个开始遍历,pre始终指向p前一个结点 
		if(p->data==x) {
			pre->next=p->next;
			delete(p);
		}
		p=p->next;
		pre=pre->next;
	}
}

 

上面介绍了单链表的简单原理。而C++在STL中也有链表相关容器list,它是一个双向链表。使用方法可以参考博客 C++中list用法详解_Donny's Blog-优快云博客_c++list 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值