双向链表也叫双链表

news2024/11/28 21:48:25

双向链表也叫双链表

双向链表也叫双链表
每个节点都有两个指针,分别指向 直接前驱节点、直接后继节点

双向链表中任意一个节点,都可以通过通过它的前驱节点和后继节点,访问其他节点

节点如下
在这里插入图片描述
节点定义
ListNode
// 节点的值
T element;
// 前置节点
ListNode preNode;
// 后置节点
ListNode nextNode;

链表提供以下方法

项目Value
PushFront(T t)将元素插入到链表第一个位置
PushBack(T t)将元素插入到链表最后一个位置
Front()第一个节点
Back()最后一个节点
MakeEmpty()清空链表
IsEmpty()判断链表是否为空
Size()获取链表中数据个数
Find(T t)查找节点
Delete(T t)删除节点
Delete(ListNode node)删除节点
InsertAsNext(ListNode node, ListNode next)将 next 插入到 node 后
Begin()迭代器开始
End()迭代器结束
Deduplicate()无序链表删除重复元素
Uniquify()有序链表删除重复元素
List Traverse()迭代遍历获取所有元素
Swap(ListNode node1, ListNode node2)交换两个节点的值
Sort(Comparison comparison)排序,comparison 是比较函数

C# 代码实现如下

    /// <summary>
    /// 链表节点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ListNode<T> where T : IComparable<T>
    {
        // 节点的值
        private T element;
        // 前置节点
        private ListNode<T> preNode;
        // 后置节点
        private ListNode<T> nextNode;

        public ListNode()
        {

        }

        public ListNode(T v)
        {
            element = v;
        }

        public ListNode(T v, ListNode<T> pre, ListNode<T> next)
        {
            element = v;
            preNode = pre;
            nextNode = next;
        }

        public T Element
        {
            get { return element; }
            set { element = value; }
        }

        public ListNode<T> PreNode
        {
            get { return preNode; }
            set { preNode = value; }
        }

        public ListNode<T> NextNode
        {
            get { return nextNode; }
            set { nextNode = value; }
        }
    }

    /// <summary>
    /// 链表迭代器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class LinkListIterator<T> where T : IComparable<T>
    {
        private ListNode<T> node;

        public LinkListIterator(ListNode<T> node)
        {
            this.node = node;
        }

        public ListNode<T> Node
        {
            get { return node; }
        }

        public T Element
        {
            get
            {
                return node.Element;
            }
        }

        /// <summary>
        /// 重写 == 方法
        /// </summary>
        /// <param name="iteratorL"></param>
        /// <param name="iteratorR"></param>
        /// <returns></returns>
        public static bool operator ==(LinkListIterator<T> iteratorL, LinkListIterator<T> iteratorR)
        {
            return null != iteratorL.node && null != iteratorR.node && iteratorL.node == iteratorR.node;
        }

        /// <summary>
        /// 重写 != 方法
        /// </summary>
        /// <param name="iteratorL"></param>
        /// <param name="iteratorR"></param>
        /// <returns></returns>
        public static bool operator !=(LinkListIterator<T> iteratorL, LinkListIterator<T> iteratorR)
        {
            return null == iteratorL.node || null == iteratorR.node || iteratorL.node != iteratorR.node;
        }

        /// <summary>
        /// 重写 ++ 方法
        /// </summary>
        /// <param name="iterator"></param>
        /// <returns></returns>
        public static LinkListIterator<T> operator ++(LinkListIterator<T> iterator)
        {
            iterator.node = iterator.node.NextNode;
            return iterator;
        }

        /// <summary>
        /// 重写 -- 方法
        /// </summary>
        /// <param name="iterator"></param>
        /// <returns></returns>
        public static LinkListIterator<T> operator --(LinkListIterator<T> iterator)
        {
            iterator.node = iterator.node.PreNode;
            return iterator;
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    /// <summary>
    /// 链表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class LinkList<T> where T : IComparable<T>
    {
        /// <summary>
        /// 头节点
        /// </summary>
        private ListNode<T> _header;
        /// <summary>
        /// 尾节点
        /// </summary>
        private ListNode<T> _trailer;  
        // 除去 头、尾,节点的个数
        private int _size;

        public LinkList()
        {
            // 为了减少操作上的复杂度
            // 头节点和尾节点一直存在,添加、删除都是在 头节点、尾节点 中间操作
            _header = new ListNode<T>();
            _trailer = new ListNode<T>();

            _header.PreNode = null;
            _header.NextNode = _trailer;

            _trailer.PreNode = _header;
            _trailer.NextNode = null;
        }

        /// <summary>
        /// 迭代器开始
        /// </summary>
        /// <returns></returns>
        public LinkListIterator<T> Begin()
        {
            return new LinkListIterator<T>(_header.NextNode);
        }

        /// <summary>
        /// 迭代器结束
        /// </summary>
        /// <returns></returns>
        public LinkListIterator<T> End()
        {
            return new LinkListIterator<T>(_trailer);
        }

        /// <summary>
        /// 第一个元素
        /// </summary>
        public ListNode<T> Front()
        {
            return Size() > 0 ? _header.NextNode : null;
        }

        /// <summary>
        /// 最后一个元素
        /// </summary>
        public ListNode<T> Back()
        {
            return Size() > 0 ? _trailer.PreNode : null;
        }

        /// <summary>
        /// 清空链表
        /// </summary>
        public void MakeEmpty()
        {
            _header.NextNode = _trailer;
            _trailer.PreNode = _header;

            _size = 0;
        }

        /// <summary>
        /// 链表为空
        /// </summary>
        public bool IsEmpty()
        {
            return _header.NextNode == _trailer;
        }

        /// <summary>
        /// 链表元素个数
        /// </summary>
        public int Size()
        {
            return _size;
        }

        /// <summary>
        /// 查找元素指针位置
        /// </summary>
        public ListNode<T> Find(T t)
        {
            ListNode<T> temp = _header.NextNode;
            while (temp != _trailer)
            {
                if (temp.Element.CompareTo(t) == 0)
                {
                    return temp;
                }
                temp = temp.NextNode;
            }
            return null;
        }

        /// <summary>
        /// 删除元素
        /// </summary>
        public void Delete(T t)
        {
            ListNode<T> node = Find(t);
            Delete(node);
        }

        public void Delete(ListNode<T> node)
        {
            if (null != node)
            {
                node.PreNode.NextNode = node.NextNode;
                node.NextNode.PreNode = node.PreNode;
                --_size;
            }
        }

        /// <summary>
        /// 将元素插入到链表第一个位置
        /// </summary>
        /// <param name="t"></param>
        public void PushFront(T t)
        {
            ListNode<T> newNode = new ListNode<T>(t);
            InsertAsPre(_header.NextNode, newNode);
        }

        /// <summary>
        /// 将元素插入到链表最后一个位置
        /// </summary>
        /// <param name="t"></param>
        public void PushBack(T t)
        {
            ListNode<T> newNode = new ListNode<T>(t);
            InsertAsPre(_trailer, newNode);
        }

        private void InsertAsPre(ListNode<T> node, ListNode<T> next)
        {
            InsertAsNext(node.PreNode, next);
        }

        /// <summary>
        /// 将 next 插入到 node 后
        /// </summary>
        /// <param name="node"></param>
        /// <param name="next"></param>
        public void InsertAsNext(ListNode<T> node, ListNode<T> next)
        {
            if (node == _trailer)
            {
                return;
            }
            next.PreNode = node;
            next.NextNode = node.NextNode;

            node.NextNode.PreNode = next;
            node.NextNode = next;

            ++_size;
        }

        /// <summary>
        /// 无序链表删除重复元素
        /// </summary>
        public void Deduplicate()
        {
            for (ListNode<T> node = _header.NextNode; node != _trailer; node = node.NextNode)
            {
                for (ListNode<T> temp = node.NextNode; temp != _trailer; temp = temp.NextNode)
                {
                    if (node.Element.CompareTo(temp.Element) == 0)
                    {
                        Delete(temp);
                    }
                }
            }
        }

        /// <summary>
        /// 有序链表删除重复元素
        /// </summary>
        public void Uniquify()
        {
            ListNode<T> node = _header.NextNode;
            while ( node != _trailer)
            {
                ListNode<T> next = node.NextNode;
                if (next != _trailer && next.Element.CompareTo(node.Element) == 0)
                {
                    Delete(next);
                    continue;
                }
                node = node.NextNode;
            }
        }

        /// <summary>
        /// 遍历
        /// </summary>
        public List<T> Traverse()
        {
            List<T> list = new List<T>();
            for (LinkListIterator<T> iterator = Begin(); iterator != End(); ++iterator)
            {
                list.Add(iterator.Element);
            }
            return list;
        }

        /// <summary>
        /// 交换两个节点位置
        /// </summary>
        public void Swap(ListNode<T> node1, ListNode<T> node2)
        {
            if (node1.NextNode == node2)
            {
                Swap(node1.PreNode, node2.NextNode, node1, node2);
            }
            else if (node2.NextNode == node1)
            {
                Swap(node2.PreNode, node1.NextNode, node2, node1);
            }
            else
            {
                Swap(node1.PreNode, node2.NextNode, node1, node2);
            }
        }

        /// <summary>
        /// 交换两个节点位置
        /// </summary>
        /// <param name="pre"></param>
        /// <param name="next"></param>
        /// <param name="node1"></param>
        /// <param name="node2"></param>
        private void Swap(ListNode<T> pre, ListNode<T> next, ListNode<T> node1, ListNode<T> node2)
        {
            Delete(node1);
            Delete(node2);

            InsertAsNext(pre, node2);
            InsertAsPre(next, node1);
        }

        /// <summary>
        /// 排序
        /// </summary>
        public void Sort(Comparison<T> comparison)
        {
            ListNode<T> begin = _header.NextNode;
            if (null == begin || begin.NextNode == _trailer)
            {
                return;
            }

            for (ListNode<T> temp = begin.NextNode; temp != _trailer; temp = temp.NextNode)
            {
                T element = temp.Element;
                ListNode<T> preNode = temp.PreNode;
                while (preNode != _header.NextNode.PreNode && comparison(preNode.Element, element) > 0)
                {
                    preNode.NextNode.Element = preNode.Element;
                    preNode = preNode.PreNode;
                }

                preNode.NextNode.Element = element;
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1603412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day12-1 | 二叉树 part-1 (Go) | 二叉树的理论基础

今日任务 二叉树的理论基础 ( 参考: 代码随想录) 二叉树种类 二叉树是一种基础数据结构&#xff0c;在算法面试中都是常客&#xff0c;也是众多数据结构的基石。二叉树的定义 和链表是差不多的&#xff0c;相对于链表 &#xff0c;二叉树的节点里多了一个指针&#xff0c; 有…

ArtCoder——通过风格转换生成多元化艺术风格二维码

简介 ArtCoder能够从原始图像&#xff08;内容&#xff09;、目标图像&#xff08;风格&#xff09;以及想要嵌入的信息中&#xff0c;生成具有艺术风格的二维码。这一过程类似于通常的图像风格转换&#xff0c;但特别针对二维码的特点进行了优化和调整。 通过这种方法&#…

MAC电脑M1安装OpenCV

最近在学习研究OpenCV&#xff0c;奈何只有mac电脑。安装OpenCV感觉还是挺麻烦的&#xff0c;所以记录一下&#xff0c;难免以后会忘记。 安装OpenCV我参考的帖子 https://www.bilibili.com/read/cv23613225/ 一、首先安装Anaconda 目前已安装不做赘述 二、启动命令窗口 方…

技术速递|.NET 智能组件简介 – AI 驱动的 UI 控件

作者&#xff1a;Daniel Roth 排版&#xff1a;Alan Wang AI 的最新进展有望彻底改变我们与软件交互和使用软件的方式。然而&#xff0c;将 AI 功能集成到现有软件中可能面临一些挑战。因此&#xff0c;我们开发了新的 .NET 智能组件&#xff0c;这是一组真正有用的 AI 支持的 …

PHP货运搬家/拉货小程序二开源码搭建的功能

运搬家/拉货小程序的二次开发可以添加许多功能&#xff0c;以增强用户体验和提高业务效率。以下是一些可能的功能&#xff1a; 用户端功能&#xff1a; 注册登录&#xff1a;允许用户创建个人账户并登录以使用应用程序。货物发布&#xff1a;允许用户发布他们需要搬运的货物信息…

win2022服务器apache配置https(ssl)真实环境实验(避坑之作)不依赖宝塔小皮等集成环境

本次实验背景&#xff1a; 完全参考官方 https://cloud.tencent.com/document/product/400/4143 文档流程&#xff0c;没有搞定&#xff0c;于是写下避坑之作。 服务器&#xff1a;腾讯云轻量应用服务器 操作系统&#xff1a; Windows Server 2022 DataCenter 64bit CN apache…

rust 学习笔记(13-19)

13 迭代器与闭包 Rust 的设计灵感来源于很多现存的语言和技术。其中一个显著的影响就是 函数式编程&#xff08;functional programming&#xff09;。函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将函数赋值给变量以供之后执行等等。 闭包&#xff08;Closu…

什么Vue?

引入vue.js的方法&#xff1a; <script src"https://cdn.jsdelivr.net/npm/vue2.6.10/dist/vue.js"></script> 例子&#xff1a; v-model&#xff1a;以v-开头的叫做指令 <!DOCTYPE html> <html lang"en"> <head><me…

Adobe Firefly是否将重新定义AI视频编辑领域?|TodayAI

Adobe最近发布了一段令人瞩目的视频&#xff0c;详细展示了其最新推出的Adobe Firefly视频模型。这一模型集成了尖端的生成式人工智能技术&#xff0c;带来了一系列颠覆性的视频编辑功能&#xff0c;引发了业界的广泛关注和讨论。 视频中的旁白充满热情地宣布&#xff1a;“Ad…

机器学习基础入门(二)(线性回归与成本函数)

目录 线性回归模型 问题 过程 模型f的选择 回归和分类比较 机器学习术语 模型训练 成本函数 介绍 设计成本函数 直观化理解成本函数 线性回归模型 问题 已知一系列房子的大小以及其对应的价格的数据&#xff0c;要求是已知房子大小预测其房子的价格 过程 一、根…

JS-43-Node.js02-安装Node.js和npm

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境&#xff0c;可以让JavaScript实现后端开发&#xff0c;所以&#xff0c;首先在本机安装Node.js环境。 一、安装Node.js 官网&#xff1a;下载 Node.js 默认两个版本的下载&#xff1a; 64位windows系统的LTS(Long Tim…

git工作流程简介及常用命令

1、git工作流程 1&#xff0e;从远程仓库中克隆或拉取代码到本地仓库(clone/pull) 2&#xff0e;从本地进行代码修改 3&#xff0e;在提交前先将代码提交到暂存区 4&#xff0e;提交到本地仓库。本地仓库中保存修改的各个历史版本 5&#xff0e;修改完成后&#xff0c;需要…

SnapGene Mac激活版 分子生物学软件

SnapGene Mac是一款功能全面、操作便捷的综合性分子生物学软件&#xff0c;专为Mac用户打造。它集成了DNA序列编辑、分析、可视化和团队协作等多种功能&#xff0c;为科研人员提供了一个高效、可靠的分子生物学研究工具。 SnapGene Mac激活版下载 在SnapGene Mac中&#xff0c;…

看图找LOGO,基于YOLOv5系列【n/m/x】参数模型开发构建生活场景下的商品商标LOGO检测识别系统

日常生活中&#xff0c;我们会看到眼花缭乱的各种各样的产品logo&#xff0c;但是往往却未必能认全&#xff0c;正因为有这个想法&#xff0c;这里我花费了过去近两周的时间采集和构建了包含50种商品商标logo的数据集来开发构建对应的检测识别系统&#xff0c;在前文中我们已经…

Python学习教程(Python学习路线+Python学习视频):Python数据结构

数据结构引言&#xff1a; 数据结构是组织数据的方式&#xff0c;以便能够更好的存储和获取数据。数据结构定义数据之间的关系和对这些数据的操作方式。数据结构屏蔽了数据存储和操作的细节&#xff0c;让程序员能更好的处理业务逻辑&#xff0c;同时拥有快速的数据存储和获取方…

游戏、app抓包

文章目录 协议app抓包游戏抓包 协议 在抓包之前&#xff0c;首先我们要对每个程序使用什么协议有个大致的了解&#xff0c;比如网页这种就是走的http协议。 在一些app中我们通过发送一个请求&#xff0c;然后服务器接受&#xff0c;响应&#xff0c;返回一个数据包&#xff0c…

VTK —— 二、教程二 - 利用vtk观察者检测多边形圆锥水平旋转360°过程(附完整源码)

代码效果 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用Vs2017代码测试&#xff08;附编译流程、附编译好的库、vtk测试源码&#xff09; 教程描述 本…

使用clickhouse-backup迁移数据

作者&#xff1a;俊达 1 说明 上一篇文章中&#xff0c;我们介绍了clickhouse-backup工具。除了备份恢复&#xff0c;我们也可以使用该工具来迁移数据。 这篇文章中&#xff0c;我们提供一个使用clickhouse-backup做集群迁移的方案。 2 前置条件 1、源端和目标端网络联通&a…

vscode 配置go环境

https://www.zhihu.com/question/486786946/answer/2723663432 注意一定要安装最新版,否则不容易debug //main.go package main //说明hello.go这个文件在main这个包中import "fmt" //导入内置包&#xff0c;可以使用其中函数等func main() {fmt.Println("Hello…

微信小程序的常用API ①

前言&#xff1a;什么是微信小程序的API&#xff1f; &#xff08;1&#xff09;微信小程序的API是由宿主环境提供的。通俗来说API是一种接口函数&#xff0c;把函数封装起来给开发者使用&#xff0c;这样好多功能都无需开发者去实现&#xff0c;直接调用即可。 &#xff08;…