数据结构之List(双向链表)的实现

链节

链表由节点连成,节点的定义如下

# pragma once
# include <iostream>template <typename T>
struct listNode {T data;listNode <T>* pred;listNode <T>* succ;listNode(){}listNode(T d, listNode<T>* p, listNode<T>* s):data(d), pred(p), succ(s){}T getData(void) { return data; }listNode<T> getPred(void) { return pred; }listNode<T> getSucc(void) { return succ; }listNode <T>* insertAsPred(const T & e){listNode <T> * tmp = new listNode <T>(e, pred, this);pred->succ = tmp;pred = tmp;return tmp;}listNode <T>* insertAsSucc(const T & e){listNode <T> * tmp = new listNode <T>(e, this, succ);succ->pred = tmp;succ = tmp;return tmp;}
};

链表的方法

方法名参数功能返回
findconst T & val, int n, listNode * p区间查找 从p往前数n个节点指针或NULL
const T & val, listNode * p区间查找 从p往前到首节点
const T & val查找
Sizevoid链表规模size
emptyvoid判空bool
firstvoid返回首节点首节点指针
clearvoid清空链表void
insertAsFirstconst T & val作为首节点插入新节点指针
insertAsLastconst T & val作为末节点插入
insertBeforeconst T & val, listNode * node在某节点前插入
insertAfterconst T & val, listNode * node在某节点后插入
removelistNode * node移除后一个节点的指针
uniquevoid无序链表唯一化删多少个
traverseT2 & visit遍历void
unique_orderedvoid有序链表唯一化删多少个
uniquevoid无序链表唯一化删多少个
uniquevoid无序链表唯一化删多少个
selectionSortvoid选择排序,范围全部void
listNode* p, int n范围从p往前数n个节点void
insertionSortvoid插入排序,范围全部void
listNode* p, int n范围从p往前数n个节点void

总结

  1. 函数的分割。插入操作就很方便。

  2. 在按指针遍历的循环中for (listNode<T> * p = head; p->succ != tail; p = p->succ,使用List<T>::remove(),是危险的。执行完remove(p)后,p将成为野指针。p=p->succ将发生错误。而Vector<T>::remove()是安全的。若非要执行remove(p),请改成p = p->succ;remove(p->pred); 本程序中也可写为p = remove(p->pred);

  3. listNode为什么定义成struct而非class,因为List要经常对每个节点的前驱与后继做修改,所以pred、succ、data都是public的,所以listNode定义为struct

  4. 有序容器和无序容器的查找的区别在于,无序find()找不到返回NULL,有序search()可以返回失败位置。

code

# pragma once
# include "listNode.h"template <typename T>
struct printList {void operator () (T* pnode){std::cout << pnode->data << std::endl;}
};template <typename T>
class List {
public:// 构造函数List() { init();}// 析构函数~List(){for (listNode<T> * currentNode = head->succ; currentNode; currentNode = currentNode->succ){delete currentNode->pred;}delete tail;}//***********************************************************只读*********************************************************// 区间查找 从p往前数n个节点的范围listNode<T> * find(const T & val, int n, listNode<T> * p) const{while (n-- && p != head && p->data != val){p = p->pred;}if (n == 0 && p == head) return NULL;else return p;}// 区间查找 从p往前到首节点的范围listNode<T> * find(const T & val, listNode<T> * p) const{while (p != head && p->data != val){p = p->pred;}if (p == head) return NULL;else return p;}// 全体查找listNode<T> * find(const T & val) const{listNode<T> * find(val, tail->pred);}//***********************************************************可写*********************************************************// 清空void clear(){for (listNode<T> * currentNode = head->succ->succ; currentNode; currentNode = currentNode->succ){delete currentNode->pred;}size = 0;head->pred = NULL;head->succ = tail;tail->pred = head;tail->succ = NULL;}// 作为首节点插入listNode<T> * insertAsFirst(const T & val) { ++size;  return head->insertAsSucc(val); }// 作为末节点插入listNode<T> * insertAsLast(const T & val) { ++size;  return tail->insertAsPred(val); }// 在某节点前插入listNode<T> * insertBefore(const T & val, listNode<T> * node) { ++size;  return node->insertAsPred(val); }// 在某节点后插入listNode<T> * insertAfter(const T & val, listNode<T> * node) { ++size;  return node->insertAsSucc(val); }// 移除listNode<T> * remove(listNode<T> * node){if (node == NULL) return NULL;--size;listNode<T> * succNode = node->pred->succ = node->succ;node->succ->pred = node->pred;delete node;return succNode;}// 唯一化int unique(void){int oldSize = size;for (listNode<T> * p = head->succ; p != tail; p = p->succ){remove(find(p->data, p->pred));}return oldSize - size;}// 基于复制的构造//***********************************************************遍历*********************************************************template <typename T2> void traverse(T2 & visit){for (listNode<T> * p = head->succ; p != tail; p = p->succ){visit(p);}}//*****************************************************针对有序链表的操作***************************************************// 有序链表唯一化int unique_ordered(void){// 如果该节点与前驱data一样,删掉前驱if (size < 2) return 0;int oldSize = size;for (listNode<T> *p = head->succ->succ; p != tail; p = p->succ){if (p->data == p->pred->data){remove(p->pred);}}return oldSize - size;}// 查找listNode<T> * search(const T & data, listNode<T> * p, int n){while (n-- && p != head && data < p->data){p = p->pred;}return p;}//***********************************************************排序*********************************************************// 插入排序void insertionSort(listNode<T>*p, int n);void insertionSort(void){ insertionSort(head->succ, size);}// 选择排序void selectionSort(listNode<T>*p, int n);void selectionSort(void) { selectionSort(head->succ, size);}protected:// 初始化双向链表void init(void){size = 0;head = new listNode<T>;tail = new listNode<T>;head->pred = NULL;head->succ = tail;tail->pred = head;tail->succ = NULL;}// 从p开始往前找n个,这些data之中最大的,且最右的listNode<T>* Max(listNode<T>* p, int n);private:listNode<T> * head;listNode<T> * tail;int size;};// 选择排序
template <typename T>
void List<T>::selectionSort(listNode<T>*p, int n)
{// 找到有序后缀(注意,初始长度为0)listNode<T>* pos = p; //一会儿要在pos之前插入for (int i = 1; i <= n; ++i) pos = pos->succ;for (int rank = 0; rank < n; ++rank, pos = pos->pred) //有序后缀的长度{// 找前缀中最大值listNode<T> * tmp_max = Max(pos->pred, n - rank);// 插入后缀最前面insertBefore(tmp_max->data, pos);remove(tmp_max);}
}// 从p开始往前找n个,这些data之中最大的,且最右的
template <typename T>
listNode<T>* List<T>::Max(listNode<T>* p, int n)
{listNode<T> * tmp_max = p;while (n-- && p != head){if (p->data > tmp_max->data) tmp_max = p;p = p->pred;}return tmp_max;
}// 插入排序
template <typename T>
void List<T>::insertionSort(listNode<T>*p, int n)
{for (int rank = 1; rank <= n; ++rank) //有序前缀的长度{listNode<T>* pos = search(p->data, p->pred, rank);insertAfter(p->data, pos);//p = p->succ;p = remove(p->pred);}
}

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

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

相关文章

Zabbix 自动发现及注册

1、依次选择 Configuratio、Discovery、Create discovery rule&#xff08;配置、自动发现、创建发现规则&#xff09; 创建客户端发现规则 2、zabbix客户端安装 agent zabbix客户端一键安装脚本 脚本参考链接 #!/bin/bash #Zabbix-Agent 5.0Zabbix_Service192.168.63.20#安…

【PHP面试题44】PHP5的版本和PHP7之间有哪些区别

文章目录 一、前言二、底层调整2.1性能提升2.2 新的引擎2.3 数据类型改进2.4 错误处理改进2.5 语言特性增加 三、应用层差异3.1 兼容性3.2 类和方法改进3.3 错误处理机制3.4 性能优化3.5 新的扩展支持 四、一些语法糖示例4.1 标量类型声明示例4.2 新增了Spaceship操作符&#x…

win11中的pagefile.sys

在C盘系统下&#xff0c;有一个命名为pagefile.sys的文件占用C盘太大的空间&#xff0c;不少用户怕删除pagefile.sys文件之后会对系统造成影响&#xff0c;而不少用户想要将pagefile.sys文件移动到D盘中。那么pagefile.sys是什么文件&#xff1f;Win10系统下pagefile.sys文件太…

【C++】list的模拟实现

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

5. MySQL - JDBC SQL 注入 博客系统(万字详解)

目录 1. 介绍 2. 使用 JDBC 连接数据库 2.1 如何使用 JDBC 连接数据库 2.2 导入的各个类 2.3 DataSource 对象的创建 2.4 从 DataSource 对象中得到 Connection 对象 2.5 创建 Statement 对象 2.6 从 ResultSet 中遍历每行结果&#xff0c;从每行中获取每列的值 2.7 代…

EIK+Filebeat+Kafka

目录 Kafka 概述 为什么需要消息队列&#xff08;MQ&#xff09; 使用消息队列的好处 消息队列的两种模式 Kafka 定义 Kafka 简介 Kafka 的特性 Kafka 系统架构 Partation 数据路由规则&#xff1a; 分区的原因 部署 kafka 集群 1.下载安装包 2.安装 Kafka 修改配…

B072-项目实战-用户模块--前台登录 三方登录

目录 前台登录-账号登录前端完成左上角显示用户信息配置前置拦截器、后置拦截器和不受限资源拦截器 三方登录-微信登录概述流程图用法代码实现步骤分析:实现准备代码前端login.htmlcallback.html 后端LoginController-微信登录LoginServiceImpl-微信登录解决回调域名不能跨域绑…

安达发|某大厂使用APS计划排程真实成功案例

在很多群里、朋友圈、公众号上可以看到&#xff0c;很多精益咨询老师认为&#xff0c;不仅ERP不啥用&#xff0c;APS更是无聊之举&#xff0c;而且肯定是用不好的。但&#xff0c;事实上可能还真不是这样的。 一个深圳的客户&#xff0c;用了APS以后&#xff0c;不仅装配的齐套…

leetcode12. 整数转罗马数字

首先这题不需要怎么考虑罗马数字顺序的问题&#xff0c;罗马转整数才需要&#xff0c;因为我模拟出来对照表就行&#xff0c;不涉及加减运算。 那怎么模拟对照表呢&#xff1f;每一个十分位的整数&#xff0c;都是两个字母的组合。那我按区间列出每个十分位的组合就ok。 直接…

鱼皮 C++ 学习路线一条龙!

大家好&#xff0c;我是鱼皮 &#x1f9d1;&#x1f3fb;‍&#x1f9b2;。 最近有很多小伙伴私信问我有没有 C 的学习路线&#xff0c;其中甚至有刚高考完的朋友&#xff01; 那就给大家分享一下吧~ 在编写本路线时&#xff0c;鱼皮参考了多位 C 专业大佬的建议&#xff0c;…

vue npm install报错如何处理

npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: eslint-plugin-vue5.2.3 npm ERR! Found: eslint6.8.0 npm ERR! node_modules/eslint npm ERR! peer eslint"> 1.6.0" from vue/cli-plugin-eslint4.4.4 这个错误…

桥梁监测需要哪些设备?

随着我国经济的发展&#xff0c;我国桥梁建设也迈上了新的台阶。截至2022年底&#xff0c;我国的公路桥梁总数达到了103.32万座。然而&#xff0c;随着在役桥梁使用时间的增长&#xff0c;承载能力受到荷载、环境以及结构退化等因素的影响&#xff0c;桥梁安全问题日益凸显。桥…

React 脚手架与react的使用

react脚手架的使用 目标&#xff1a;掌握如何使用react脚手架创建react项目 内容 create react app&#xff08;CRA&#xff09;是FaceBook的React团队官方出的一个构建React应用的脚手架工具命令&#xff1a;npx create-react-app react-basic react-basic 表示项目名称&am…

vue3和gin框架实现简单的断点续传

vue3和gin框架实现简单的断点续传 前端代码 Test.vue <template><div><inputtype"file"ref"uploadRef"change"upload"multiple/><templatev-for"item in fileList":key"item.key"><br><…

spring复习:(39)注解方式的ProxyFactoryBean

一、定义接口 package cn.edu.tju.study.service;public interface MyService {void myMethod(); }二、定义实现类&#xff1a; package cn.edu.tju.study.service;public class MyServiceImpl implements MyService{Overridepublic void myMethod() {System.out.println(&qu…

MySQL的存储引擎

1. 有哪些常见的存储引擎&#xff1f; MyISAM&#xff1a;这种引擎是mysql最早提供的。这种引擎又可以分为静态MyISAM、动态MyISAM 和压缩MyISAM三种&#xff0c;不管是何种MyISAM表&#xff0c;目前它都不支持事务&#xff0c;行级锁和外键约束的功能。 MyISAM Merge引擎&…

Redis 读写分离 使用redisTemplate执行lua脚本时,报错处理

项目框架说明 项目配置 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.4</version></parent>....<dependency><groupId>org.springfra…

(学习笔记-TCP基础知识)TCP与UDP区别

UDP UDP不提供复杂的控制机制&#xff0c;利用IP提供面向[无连接]的通信服务。 UDP协议非常简单&#xff0c;头部只有8个字节(位)&#xff0c;UDP的头部格式如下&#xff1a; 目标和源端口&#xff1a;主要是告诉UDP协议应该把报文发给哪个进程包长度&#xff1a;该字段保存了…

TinyKv流程梳理三

split流程 处理协程启动 func (bs *Raftstore) startWorkers(peers []*peer) {ctx : bs.ctxworkers : bs.workersrouter : bs.routerbs.wg.Add(2) // raftWorker, storeWorkerrw : newRaftWorker(ctx, router)go rw.run(bs.closeCh, bs.wg)sw : newStoreWorker(ctx, bs.store…

基于Web API drap事件的简单拖拽功能

基于Web API drap事件的简单拖拽功能 效果示例图代码示例 效果示例图 代码示例 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style type"text/css">* {padding: 0px;margin: 0px;box-s…