从头开始学数据结构----<链表>

本文详细对比了数组和链表这两种基础数据结构,阐述了它们在内存分配、操作效率、扩展性等方面的差异。在查询效率上,数组具有优势,而链表在插入和删除操作上更胜一筹。文章还提到了数组链表这种结合两者优点的数据结构,并给出了双向链表的代码实现,展示了如何进行插入、删除等操作。对于需要频繁增删查的场景,链表是更好的选择,而在已知数据规模且主要进行查询的情况下,数组更为合适。

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

链表

链表和数组作为算法中的两个基本数据结构,在程序设计过程中经常用到。尽管两种结构都可以用来存储一系列的数据,但又各有各的特点。

数组 VS 链表

1. 数组

  • 所申请的内存空间,必须是线性连续,且申请的空间大小必须提前确定。
  • 插入和删除操作代价比较大,需要该位置后面的数据都向后移动,留出一个空位进行插入,或者都向前移动,把该空位的数据进行覆盖(也就是删除)。
  • 查询代价较小,数组是连续存储的,知道该数组名称,可根据下标直接查询;
  • 不利于扩展,数组空间是提前申请的,当存储空间不够时,需要重新申请空间。

2、链表

  • 申请内存中存储空间,不要求连续,只需要保存下一个存储空间的内存地址即可。
  • 插入和删除操作比较容易,只需要改变指针的指向即可。
  • 查询代价较大,不具备随机访问能力,需要从头到尾遍历查找。
  • 扩展性较好,不用提前指定大小,插入删除比较随意。

3、时间复杂度

操作数组链表
查询O(1)O(n)
插入O(n)O(1)
删除O(n)O(1)

对于频繁查询的场景,选用数组;对于频繁插入删除的场景,选用链表;频繁查询也频繁增删呢?选用数组链表。

如果你有创造性思维的话,数组链表其实是一种更好的数据结构,集数组和链表优点于一身的数据结构,有兴趣的读者下来自行研究(这绝对是亮点)。

内存空间利用率:每一个数组单元是 100% 存储数据,每一个链表单元是存储数据 + 存储指针,数组对于内存的利用上大于链表(当然了,还需要看是否提前知道要存储数据个数)。

链表

链表所分配的空间在内存上不一定连续,但是链表具有其天然优势。

链表分为 4 种情况:单链表,单循环链表,双链表,双循环链表,一定要反复琢磨,理解清楚我下面画的模型,这些模型是本文核心所在;

各自模型如下:
(1)、单链表
在这里插入图片描述
(2)、单循环链表
在这里插入图片描述
(3)、双链表
在这里插入图片描述
(4)、双循环链表在这里插入图片描述

  1. 单链表
    单链表分为 2 种情况:带头结点链表 + 不带头结点链表。
    带头结点链表:第一个节点不存储真实数据在这里插入图片描述
    不带头结点链表:第一个节点存储真实数据
    在这里插入图片描述
    链表上常见操作:创建链表、插入链表,删除链表,查找数据,修改数据,销毁链表…

链表的各种操作,只要能在纸上画出模型,掌握好几个指针的指向,就能将代码写出来。

  1. 双向循环链表
    (1)、模型如下:
    在这里插入图片描述
    下面用代码简单实现一个双向链表,其他的链表可以自行实现,只要掌握了一个,其他的都是一样的。
    DoubleLink.h
#ifndef _DOUBLELINK_H
#define _DOUBLELINK_H

#include <iostream>
using namespace std;

template < typename Type>
class DoubleLinkedList;

template<typename Type>
class DoubleLinkedListNode
{
	friend class DoubleLinkedList<Type>;
public:
	DoubleLinkedListNode(Type x = 0)
	{
		data = x;
		prev = next = NULL;
	}
	~DoubleLinkedListNode()
	{
	}
private:
	Type data;			//数据
	DoubleLinkedListNode* prev;	//指向前一结点指针
	DoubleLinkedListNode* next;	//指向下一结点指针
};

template<typename Type>
class DoubleLinkedList
{
public:
	DoubleLinkedList()
	{
		DoubleLinkedListNode<Type>* pTemp = new DoubleLinkedListNode<Type>;
		first = last = pTemp;
		pTemp->next = first;
		pTemp->prev = last;
		size = 0;
	}
	~DoubleLinkedList()
	{

	}
public:
	//尾部插入
	bool push_back(const Type& temp);
	//打印所有
	void print_list() const;
	//头部插入
	bool push_front(const Type& temp);
	//按值插入
	bool insert_val();
	//删除最后一个结点
	bool pop_back();  
private:
	DoubleLinkedListNode<Type> *first;		//永远指向链表的头结点
	DoubleLinkedListNode<Type> *last;		//永远指向链表的尾结点
	size_t size;  //统计结点个数,不算没有数据的第一个;
};

template<typename Type>
bool DoubleLinkedList<Type>::pop_back()
{
	DoubleLinkedListNode<Type> *pTemp1 = last->prev;
	DoubleLinkedListNode<Type> *pTemp2 = last;
	pTemp1->next = first;
	first->prev = pTemp1;
	last = pTemp1;
	--size;

	delete pTemp2;
	pTemp2 = NULL;
	return true;
}

template<typename Type>
bool DoubleLinkedList<Type>::insert_val()
{
	int number1;
	int number2;
	
	std::cout << "请输入要插入位置的值 :";
	std::cin >> number1;
	std::cout << "请输入要插入的数据:";
	std::cin >> number2;
	DoubleLinkedListNode<Type> *pTemp = first->next;
	DoubleLinkedListNode<Type> *pTemp2 = new DoubleLinkedListNode<Type>(number2);
	while (pTemp != first)
	{
		if (pTemp->data == number1)
		{
			pTemp2->prev = pTemp;
			pTemp2->next = pTemp->next;
			pTemp->next->prev = pTemp2;
			pTemp->next = pTemp2;
			++size;
			break;
		}
		pTemp = pTemp->next;
	}
	return true;
}

template<typename Type>
bool DoubleLinkedList<Type>::push_front(const Type& temp)
{
	DoubleLinkedListNode<Type> *pTemp = new DoubleLinkedListNode<Type>(temp);
	pTemp->next = first->next;
	pTemp->prev = first;
	first->next->prev = pTemp;
	first->next = pTemp;
	++size;
	return true;
}

template<typename Type>
void DoubleLinkedList<Type>::print_list() const
{
	DoubleLinkedListNode<Type> *pTemp = first->next;
	while (pTemp != first)
	{
		std::cout << pTemp->data << "-->";
		pTemp = pTemp->next;
	}
	std::cout << "End" << std::endl;
}

template<typename Type>
bool DoubleLinkedList<Type>::push_back(const Type& temp)
{
	DoubleLinkedListNode<Type> *pTemp = new DoubleLinkedListNode<Type>(temp);
	pTemp->next = first;
	pTemp->prev = last;
	first->prev = pTemp;
	last->next = pTemp;
	last = pTemp;
	++size;
	return true;
}

#endif // !_DOUBLELINK_H

main.cpp

#include "DoubleLink.h"

int main()
{
	DoubleLinkedList<int> dc;
	
	for (int i = 0; i < 10; i++) 
	{
		dc.push_back(i);
	}
	
	dc.push_front(-2);
	dc.print_list();
	dc.insert_val();  //均是前插
	dc.print_list();
	dc.pop_back();
	cout << "删除最后一个结点时如下: " << endl;
	dc.print_list();
	return 0;
}

运行结果如下:
在这里插入图片描述
对源码感兴趣的话可以看看STL中List的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值