当前位置: 首页 > news >正文

采用哨兵节点的C++双链表实现

#include<iostream>

#include<string>

#include<stdexcept>

using namespace std;

template<typename E>

class Dlist{

struct Node{

E val;

Node *next;//后驱

Node *prev;//前驱

Node(const E& value):val(value),next(nullptr),prev(nullptr){}

};

Node *head;//哨兵头

Node *tail;//哨兵尾

int size;

//检查索引是否为合法的元素索引 (0,size-1)

bool isElementIndex(int index)const{

return index>=0 &&index<size;

}

//检查索引是否为合法的插入位置(0,size]

bool isPositionIndex(int index)const{

return index>=0 &&index<=size;

}

void checkElementIndex(int index)const{

if(!isElementIndex(index)){

throw out_of_range("Index: "+to_string(index)+",size"+to_string(size));

}

}

void checkPositionIndex(int index)const{

if(!isPositionIndex(index)){

throw out_of_range("Index: "+to_string(index)+",size"+to_string(size));

}

}

Node *getNode(int index)const{

if(index<size/2){ //根据索引位置决定从头找还是从尾找

Node *p=head->next; //头节点向后遍历

for(int i=0;i<index;i++){

p=p->next;

}

return p;

}

else{

Node *p=tail->prev; //尾节点向前遍历

for(int i=size-1;i>index;i--){

p=p->prev;

}

return p;

}

}public:

Dlist(){

head=new Node(E()); // 创建头哨兵

tail=new Node(E()); // 创建尾哨兵

head->next=tail; //初始状态 头指向尾 尾指向头

tail->prev=head;

size=0;

}

~Dlist(){

while(size>0){

removeFirst();

}

delete head;

delete tail;

}

void addFirst(const E& e){

Node *newNode=new Node(e);

Node *temp=head->next;//暂存第一个真实结点

temp->prev=newNode;

newNode->next=temp;

head->next=newNode;

newNode->prev=head;

size++;

}

void addLast(const E& e){

Node* newNode=new Node(e);

Node* temp=tail->prev; //暂存最后一个真实节点

temp->next=newNode;

newNode->prev=temp;

newNode->next=tail;

tail->prev=newNode;

size++;

}

void insert(int index,const E& element){

checkPositionIndex(index);

if(index==size){

addLast(element);

return ;

}

//找到前驱

Node *p=getNode(index);

Node *prev=p->prev;

Node *newNode=new Node(element);

// 将 newNode 插入到 prev 和 p 之间

p->prev=newNode;

prev->next=newNode;

newNode->prev=prev;

newNode->next=p;

size++;

}

// 获取链表当前元素个数

int size1() const{

return size;

}

// 判断链表是否为空

bool isEmpty()const{

return size==0;

}

E removeFirst(){

if(isEmpty()){

throw out_of_range("No elemnets to remove");

}

Node *x=head->next;

Node *temp=x->next;

head->next=temp;

temp->prev=head;

E val=x->val;

x->prev=nullptr;

x->next=nullptr;

delete x;

size--;

return val;

}

E removeLast(){

if(isEmpty())

throw out_of_range("No elements to remove");

Node *x=tail->prev;

Node *temp=x->prev;

tail->prev=temp;

temp->next=tail;

E val=x->val;

x->prev=nullptr;

x->next=nullptr;

delete x;

size--;

return val;

}

E remove(int index){

checkElementIndex(index);

Node *x=getNode(index); // 找到目标节点

Node *prev=x->prev;

Node *next=x->next;

// 将目标节点的前驱和后继相连 实现摘除目标节点

prev->next=next;

next->prev=prev;

E val=x->val;

x->prev=nullptr;

x->next=nullptr;

delete x;

size--;

return val;

}

// 获取第一个元素

E getFirst()const{

if(isEmpty()){

throw out_of_range("No elements in the list");

}

return head->next->val;

}

// 获取最后一个元素

E getLast()const{

if(isEmpty()){

throw out_of_range("No elements in the list");

}

return tail->prev->val;

}

// 获取指定位置的元素

E get(int index) const {

checkElementIndex(index);

Node* p = getNode(index);

return p->val;

}

// 修改指定位置的元素,并返回旧值

E set(int index,const E& element){

checkElementIndex(index);

Node *p=getNode(index);

E oldval=p->val;

p->val=element;

return oldval;

}

//打印链表内容

void print()const{

cout<<"size="<<size<<endl;

Node *p=head->next;// 从第一个真实节点开始

while(p!=tail){ // 遇到尾哨兵即停止

cout<<p->val;

if(p->next!=tail){

cout<<"<->";// 非最后一个元素时打印连接符

}

p=p->next;

}

cout<<"->null"<<endl;

}

};


int main(){

Dlist<int>list;

list.addLast(1);

list.addFirst(0);

list.addLast(2);

list.insert(2,100);

cout<<"初始链表:"<<endl;

list.print();

cout<<"removeFirst:"<<list.removeFirst()<<endl;

cout<<"removeLast:"<<list.removeLast()<<endl;

cout<<"remove(1):"<<list.remove(1)<<endl;

cout << "\n删除后链表:" << endl;

list.print();

cout<<"getFirst:"<<list.getFirst()<<endl;

cout<<"getLast:"<<list.getLast()<<endl;

cout<<"get(0)"<<list.get(0)<<endl;

cout << "\nset(0, 999) 旧值: " << list.set(0, 999) << endl;

cout<<"修改后:"<<endl;

list.print();

cout<<"\nsize:"<<list.size1()<<endl;

cout<<"isEmpty:"<<list.isEmpty()<<endl;

return 0;

}

http://www.jsqmd.com/news/1141565/

相关文章:

  • 服装点胶点钻设备选型避坑:一个五年工艺师的控制系统观察笔记
  • N_m3u8DL-CLI-SimpleG:图形化M3U8视频下载器完整使用指南
  • IS31FL3731与PIC18F4585的LED矩阵控制方案
  • 如何让GitHub下载速度飙升10倍:Fast-GitHub插件终极配置指南
  • AMD Ryzen终极调试指南:SMUDebugTool完全免费开源工具使用教程
  • 算法初学者解决删除链表倒数的节点(力扣19题)(双指针)
  • 京东云Coding Plan Lite与Pro版深度对比:开发者如何按需选择构建环境
  • LTC6903与PIC24EP构建高精度数字控制振荡器方案
  • STM32与MAX9744构建高效D类音频放大系统
  • AltDrag完整指南:如何用Alt键彻底改变你的Windows窗口操作体验
  • B站视频下载神器:三步解锁大会员4K与充电专属内容
  • STM32与MP8859实现智能电源管理方案
  • 企业微信会话存档技术选型:自研 vs 第三方服务商的 TCO 深度分析
  • STM32与LARA-R6401 LTE模块的硬件协同设计与优化
  • Web安全三大漏洞CRLF、CSRF、SSRF:从原理到实战防御指南
  • Krea 2图像生成模型:从基础原理到API部署与本地自托管实践
  • Rufus 4.1 全界面参数完整详解
  • ADS122U04与PIC18LF46K40高精度信号采集方案
  • M-LOAM 与 LOAM/LIO-SAM 对比:3 种激光SLAM方案在4类场景下的精度与鲁棒性分析
  • 3步解锁网易云音乐NCM格式:告别设备限制的音乐自由之旅
  • STM32与TB9051FTG实现低噪声直流电机控制方案
  • pycharm2023.2.5分享
  • STM32F746ZG与171010550的DC-DC降压电源设计实战
  • 撕下 MyBatis 的行业遮羞布:一款违背框架第一性原理的逆向设计产物
  • 泊松积分与伽马函数:3个核心公式在概率论与物理建模中的实战应用
  • LoRA论文关键实验复现:低秩适配究竟在哪些任务上真正有效
  • 腾讯云 EdgeOne 免费版 CDN 套餐,亲测可领多个!
  • GWAS数据整合的终极指南:如何用gwasglue快速连接基因组分析工具
  • 缠论量化分析新革命:5分钟掌握通达信自动画线插件
  • MAX9744 D类音频放大器与PIC18F86J10的高效音频系统设计