基础数据结构【链表:动态链表,(结构体,一维数组)静态链表、STL list】

本文详细探讨了链表数据结构,包括单向和双向链表的特点,动态链表的动态调整和内存管理,以及静态链表的空间利用与性能优势。还通过约瑟夫问题展示了链表在实际问题中的应用。
摘要由CSDN通过智能技术生成

链表

链表是一种数据结构,其特点主要包括以下几点:

  1. 链接性:链表中的每个节点包含一个指针,指向下一个节点(单向链表)或前一个节点(双向链表)。通过这种链接关系,可以将一系列节点按照特定顺序连接在一起

  2. 动态性:链表的大小可以动态地调整,可以动态地添加或删除节点,而不需要像数组那样需要提前申请固定大小的内存空间

  3. 灵活性:链表可以在任何位置插入或删除节点,而不会影响其他节点的位置,因为每个节点都包含指针信息,可以直接访问相邻节点。

  4. 内存空间的分散性:链表的节点在内存中可以分散存储,不要求一块连续的内存空间。这也是链表可以动态调整大小的原因。

  5. 随机访问性较差:链表的节点通过指针链接在一起,所以在访问特定位置的节点时,需要从头节点开始遍历,直到找到目标位置。因此,链表的随机访问时间复杂度为O(n),相对于数组的O(1),效率较低。

总的来说,链表的特点主要体现在链接性、动态性和灵活性上,适用于频繁的插入和删除操作,但不适用于频繁的随机访问操作

循环链表

链表一般是循环链表,首尾相连!

使用链表的方式:

  • STL list【标准模板库中链表】
  • 动态链表
  • 静态链表

动态链表

动态链表是一种数据结构,它允许在运行时动态地添加、删除和访问数据。

【临时分配链表结点、使用完毕后释放链表结点】

与数组相比,动态链表不需要预先定义大小,可以根据需要动态分配内存,从而节省空间。

  • 优点:能及时释放空间,不使用多余内存。
  • 缺点:容易出错。

总结来说,动态链表是一种灵活且高效的数据结构,广泛应用于各种算法和系统中。它可以在运行时动态地管理数据,适用于需要频繁插入、删除和访问数据的场景

洛谷练习—P1996约瑟夫问题

题目详情:
n个人围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

 输入格式:输入两个整数n,m。

输出格式:输出一行n个整数,按顺序输出每个出圈人的编号。
提示:1<m, n <100.

理解:

  1. n个人围成一圈:用循环链表
  2. 每遍历m个人,输出第m个节点,并删除
  3. 直到n个人都被删除。
#include<iostream>
using namespace std;
struct node{
	int data;
	node *next;
};
 
int main(){
	int n,m;
	scanf("%d%d",&n,&m); 
	node *head,*p,*now,*prev;
	head=new node; head->data=1; head->next=NULL;//分配节点一,值为1 
	now=head;//当前节点为头节点
	for(int i=2;i<=n;i++){
		p=new node;
		p->data=i;
		p->next=NULL;
		now->next=p;
		now=p; 
 	}
	now->next=head;//最后一个指向第一个 【形成循环链表】
	//以上建立链表
	

	now=head,prev=head;
	while((n--)>1){//遍历所有节点
		for(int i=1;i<m;i++){//数到m,停下
			prev=now;
			now=now->next; 
		}
		printf("%d ",now->data);//输出
		//输出并删除此元素 
        prev-> next=now->next;
		delete now;
		now=prev->next;
		
	}
	printf("%d",now->data);//打印最后一个节点
	delete now; 
	return 0;
}

静态链表

静态链表是一种基于数组的数据结构,用于模拟链表的操作。

它的实现原理是通过数组的索引来表示链表中的结点,数组中的每个元素都有两个属性,一个是存储的数据值,另一个是指向下一个结点在数组中的索引。

注意:算法竞赛中常用静态链表,加快编码速度。

静态链表相对于动态链表的缺点是空间利用率低,因为需要提前分配一个固定大小的数组来存储链表,如果链表的元素数量超过了数组的大小,就需要重新分配更大的数组来存储链表。

静态链表的优点是插入和删除操作的时间复杂度为O(1),而动态链表的插入和删除操作的时间复杂度为O(n)。所以在某些场景下,静态链表的性能更好。

用结构体数组实现静态链表

#include<iostream>
using namespace std;

const int N = 105;

struct node
{
	int id, nestid;
	//int data;
}node[N];

void main() {
	int n, m; cin >> n >> m;
	node[0].nestid = 1;
	for (int i = 1; i <= n; i++) {
		node[i].id = i;
		node[i].nestid = i + 1;
	}
	node[n].nestid = 1;//循环链表:收尾相连

	int now = 1, prev = 1;
	while ((n--) > 1) {
		for (int i = 1; i < m; i++) {
			prev = now;
			now = node[now].nestid;
		}
		cout << node[now].id<<" ";
		node[prev].nestid = node[now].nestid;
		now = node[prev].nestid;
	}
	//直到只剩一个元素停止循环
	cout << node[now].id;
}

用一维数组

这个是最简单的实现方法,一维数组nodes[i]中,i存节点的值,nodes[i]存下一个节点。

#include<iostream>
using namespace std;

const int N = 105;

void main() {
	
	int n, m; cin >> n >> m;

	int nodes[N];
	for (int i = 1; i <= n - 1; i++) {
		nodes[i] = i + 1;
	}
	nodes[n] = 1;

	int now = 1, prev = 1;
	while ((n--) > 1) {
		for (int i = 1; i < m; i++) {
			prev = now;
			now = nodes[now];
		}
		cout << now << " ";
		nodes[prev] = nodes[now];
		now = nodes[prev];
	}
	cout << now;
}

STL list 链表

逻辑跟上面的相同

遍历用迭代器:iterator

删除erase(),查找end()begin()

void main() {
	
	int n, m; cin >> n >> m;

	list<int>node;//建立链表
	for (int i = 1; i <= n; i++) {
		node.push_back(i);//初始化:插入队尾
	}
	list<int>::iterator it = node.begin();//遍历:迭代器

	while (node.size()> 1) {
		for (int i = 1; i < m; i++) {
			it++;
			if (it == node.end()) {
				it = node.begin();
			}
		}
		cout << *it << " ";
		list<int>::iterator next = ++it;
		if (next == node.end()) {
			next = node.begin();
		}
		node.erase(--it);//删除节点
		it = next;
		
	}
	cout << *it;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值