数据结构:链表

本文深入探讨了链表这一重要的数据结构,包括单链表、双向链表和循环链表。链表允许动态添加和删除节点,插入和删除操作的时间复杂度为O(1),但查找操作为O(n)。文章通过代码示例展示了如何在C++中实现链表的基本操作,并对比了链表与顺序表在空间和时间效率上的差异。此外,还提到了循环链表的特性,使表处理更为灵活。
摘要由CSDN通过智能技术生成

顺序表的链式存储(链表)

链表是一种常见的数据结构,由一系列节点组成。每个节点包含两部分:数据和指向下一个节点的指针。

链表中的节点通过指针连接在一起,形成一个线性序列。与数组不同,链表的节点在内存中可以不连续存储,因此可以动态地添加或删除节点,而无需移动其他节点。

常见的链表类型有单链表、双向链表和循环链表。

链表的优点是插入和删除节点的时间复杂度为O(1),而不受数据规模的限制。然而,链表在查找特定节点时需要顺序遍历,时间复杂度为O(n)。

需要注意的是,链表相对于数组在访问任意节点的效率较低,且占用的额外空间较多(每个节点需要存储指针)。因此,在选择数据结构时,要根据具体的需求进行权衡和选择。

单链表

如果序列中的节点只包含指向后继节点的链接,则该链表称之为单向链表

下面我们来了解链表的基本操作:

1. 插入

在这里插入图片描述

2. 删除

在这里插入图片描述

下面我们给出单向链表的代码,其中包含:增(头插入、尾插入);删(删除第一个节点、删除最后一个节点,删除指定数据节点);查(查找特定数据是否在链表中),能查既能改。

#include <iostream>

using namespace std;
/*
data储存数据
next存储指针地址
SingleLinkedList()声明一个单一节点,无赋值,next指向空地址
IntSLLLNode(el, prt)声明一个节点,data=el,next指向prt;
*/
class SingleLinkedList {//表中的节点
public:
	int data;
	SingleLinkedList* next;
	SingleLinkedList() {//函数重载
		next = 0;
	}
	SingleLinkedList(int el, SingleLinkedList* ptr = 0) {//函数重载
		data = el;
		next = ptr;
	}
};

class LinkedListAccess {//访问链表
private:
	SingleLinkedList* head, * tail;//分别指向表中的第一个节点和最后一个节点
public:
	LinkedListAccess() {
		head = tail = 0;
	}
	~LinkedListAccess();
	int isEmpty() {//链表是否为空链表
		return head == 0;
	}
	void addToHead(int);//头插入
	void addToTail(int);//尾插入
	int deleteFromHead();//删除第一个节点
	int deleteFromTail();//删除最后一个节点
	void deleteNode(int);//删除特定数据节点
	bool isInList(int);//查找特定数据是否在链表中
	void outputNode();//输出链表中的所有数据
};

LinkedListAccess::~LinkedListAccess()//删除头指针
{
	for (SingleLinkedList* p; !isEmpty(); ) {
		p = head->next;
		delete head;
		head = p;
	}
}

void LinkedListAccess::addToHead(int el)
{
	head = new SingleLinkedList(el, head);
	if (tail == 0) tail = head;
}

void LinkedListAccess::addToTail(int el)
{
	if (tail != 0) {
		tail->next = new SingleLinkedList(el);
		tail = tail->next;
	}
	else head = tail = new SingleLinkedList(el);
}

int LinkedListAccess::deleteFromHead()
{
	int el = head->data;
	SingleLinkedList* temp = head;
	if (head = tail) head = tail = 0;
	else head = head->next;
	delete temp;
	return el;
}

int LinkedListAccess::deleteFromTail()
{
	int el = tail->data;
	if (head == tail) {
		delete tail;
		head = tail = 0;
	}
	else {
		SingleLinkedList* temp;
		for (temp = head; temp->next != tail; temp = temp->next);
		delete tail;
		tail = temp;
		tail->next = 0;
	}
	return el;
}

void LinkedListAccess::deleteNode(int el)
{
	if (head != 0) {
		if (head == tail && el == head->data) {
			delete head;
			head = tail = 0;
		}
	}
	else if(el == head->data){
		SingleLinkedList* temp = head;
		head = head->next;
		delete temp;
	}
	else {
		SingleLinkedList* pred, *temp;
		for (pred = head, temp = head->next; temp != 0 && !(temp->data == el); pred = pred->next, temp = temp->next);
		if (temp != 0) {
			pred->next = temp->next;
			if (temp == tail) tail = pred;
			delete temp;
		}
	}
}

bool LinkedListAccess::isInList(int el)
{
	SingleLinkedList* temp;
	for(temp = head; temp != 0 && !(temp->data == el); temp = temp->next);
	return temp != 0;
}

void LinkedListAccess::outputNode()
{
	SingleLinkedList* temp;
	for (temp = head; temp != 0; temp = temp->next) {
		cout << temp->data << " ";
	}
}

int main() {
	LinkedListAccess a;
	a.addToHead(1);
	a.addToHead(2);
	a.addToTail(3);
	a.outputNode();
	return 0;
}

循环链表

循环链表:是一种头尾结点相连接的链表。特点是最后一个结点的指针域指向链表的头结点,整个链表的指针域链接成一个环。

从循环链表的任意一个结点出发都可以找到链表中的其它结点,是得表处理更加灵活

循环链表的简单修改:

  1. 判断是否是空链表: h e a d − > n e x t = = h e a d head->next==head head>next==head
  2. 判断是否是表尾结点: p − > n e x t = = h e a d p->next==head p>next==head

双向链表

双向链表:是构成链表的每个结点中设立两个指针域,一个指向其直接前驱的指针域 p r i o r prior prior,一个指向其直接后续的指针域 n e x t next next

双向链表是为了克服单链表的单向性的缺陷而引入的

顺序表和链表的比较

空间的比较

  1. 存储分配的方式:顺序表的存储空间是一次性的分配,链表的存储空间是多次分配的。
  2. 存储密度( = 结点值域所占的存储量 结点结构所占的存储总量 ):顺序表 = 1 ,链表 < 1 存储密度(=\frac{结点值域所占的存储量}{结点结构所占的存储总量}):顺序表=1,链表<1 存储密度(=结点结构所占的存储总量结点值域所占的存储量):顺序表=1,链表<1

时间的比较

  1. 存取方式:顺序表可以随机存取,也可以顺序存取;链表只能顺序存取。
  2. 插入和删除是移动元素的个数:顺序表平均移动一半元素;链表不需要移动元素,只需要修改指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星*湖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值