数据结构 -- 链表

本文介绍了链表的两种常见形式:单链表和循环链表。单链表通过头指针访问,操作尾部元素需要遍历整个链表,适合频繁的插入和删除操作。循环链表则允许从任意节点开始遍历,通过尾指针访问最后一个节点的时间复杂度为O(1)。此外,还提到了双向链表,它的灵活性更高但占用更多存储空间。
摘要由CSDN通过智能技术生成

单链表(ForwardList)

链表是链式存储结构的线性表的实现,由于内存地址不连续,所以链表不仅要有数据域,还要存储后继结点指针,如果一个结点只有一个指向后继结点的指针域,那么该线性表称为单链表

头指针与头结点

头指针中存储的是第一个结点的内存地址,通过头指针找到第一个结点,之后通过第一个结点的指针域可以找到第二个结点,以此类推,可以找到链表的最后一个结点,最后一个结点的指针域为空(nullptr)
为了更方便的对链表进行操作,引入了一个头结点的概念,头结点和普通结点一样,分为数据域和指针域,数据域可以不存东西也可以存如线性表的长度等附加信息,指针域存储的是第一个结点的内存地址
头指针和头结点的对比如下:
头指针

  • 头指针是指链表指向第一个结点的指针,若链表有头结点,则指向头结点
  • 头指针是链表的必要元素

头结点

  • 头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可以存放链表的长度)
  • 有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了
  • 头结点不一定是链表必须要素

如下实现使用头指针操作链表,遍历链表只能从头指针开始,所以访问链表中第一个结点的时间复杂度为O(1),访问最后一个结点的时间复杂度为O(N)

核心函数如下:

函数 功能 时间复杂度
push_front 向链表头部添加元素 O(1)
pop_front 移除链表头部的元素 O(1)
push_back 向链表尾部添加元素 O(N)
pop_back 移除链表尾部的元素 O(N)

单链表操作尾部的元素需要从头部遍历到尾部之后才能操作,所以时间复杂度为O(N)
当然可以维护一个尾指针指向最后一个结点,但是这相当于空间换时间

#ifndef FORWARDLIST_H_
#define FORWARDLIST_H_

#include <iostream>

#include <tools/base/copyable.h>
#include <tools/base/noncopyable.h>

template <typename T>
class ForwardList : copyable {
private:
	struct Node : noncopyable {
		T data;
		Node *next;

		Node(T elem) : data(elem), next(nullptr) {}
	};

public:
	ForwardList() : 
		m_head(nullptr), 
		m_size(0){}                                 // 默认构造函数

	ForwardList(const ForwardList& other) :         // 拷贝构造函数
		m_head(nullptr), 
		m_size(other.size())
	{         
		if(other.empty()){
			return;
		}

		m_head = new Node(other.head()->data);
		if(other.size() == 1){
			return;
		}

		Node *preNode = m_head;
		Node *selfNode;
		Node *otherNode = other.head()->next;
		while(otherNode != nullptr){
			selfNode = new Node(otherNode->data);
			preNode->next = selfNode;
			preNode = preNode->next;
			otherNode = otherNode->next;
		}
	}

	~ForwardList(){
		Node *curNode = m_head;
		Node *nextNode;
		while(curNode != nullptr){
			nextNode = curNode->next;
			delete curNode;
			curNode = nextNode;
		}
	}

	int size() const {
		return m_size;
	}

	bool empty() const {
		return m_size == 0;
	}

	Node *head() const {
		return m_head;
	}

	void push_front(T elem){                        // 向链表头部添加元素
		Node *node = new Node(elem);
		node->next = m_head;
		m_head = node;

		++ m_size; 
	}

	void pop_front(){                               // 移除链表头部的元素
		if(m_head == nullptr){
			return;
		}

		Node *node 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值