C++数据结构之循环链表

循环链表

在这里插入图片描述

如上所示,这里200,500都是地址,而1,2,3,4,5是数据,因此头节点是不存储数据的。

这里头节点不存储数据,不代表循环链表的头节点头都不存储数据,按照你自己的需求和喜好进行设计即可。


废话不多说,直接上干货

1. 循环链表的结构定义
typedef struct Node{

    int data;
    Node* next;
    Node():data(0),next(this){}; 
    Node(int x, Node *node):data(x),next(node){}; 

}*ListNode;

上述定义了循环链表结构,初始化只需要调用默认构造即可。

  • 这里采用初始化列表的方式初始化Node,不仅仅是因为这样写简洁方便,而是这种方式在有些时候是比在函数体里面初始化更加的高效。
  • 使用typedef的方式在下方定义的*ListNode是一个结构体类型而不是一个变量。
  • this指针是一个指向自己的指针。
2. 建立一个线性链表

因为这里我们写了链表的一个有参构造,这样初始化链表就变得非常简单。

template<typename T>
void CreateList(ListNode &link_list, T arr, int len){
    Node* p = link_list;
    for(int i=0; i<len; i++){
        p->next = new Node(arr[i], link_list);
        p = p->next;
    }
}

void ShowList(const ListNode &link_list){
    Node* p = link_list->next;
    while(p != link_list){
        cout << p->data << "\t";
        p = p->next;
    }
    cout << endl;
}

直接调用有参构造就可以了。

查找节点

查找节点又分按值查找和按位查找,具体代码如下所示

//按值查找节点
Node* FindValue(const ListNode &link_list, int val){
    Node *p = link_list->next;
    while(link_list != p){
        if(p->data == val) return p;
        p = p->next;
    }
    return NULL;
}

//按索引查找节点
Node* FindIndex(const ListNode &link_list, int index){
    Node *p = link_list->next;
    int count = 0;
    while(link_list != p){
        if(count == index) return p;
        p = p->next;
        count++;
    }
    return NULL;
}
修改节点

只需要判断什么时候转了一圈即可

void ChangeNode(ListNode &link_list,int index, int val){
    int count = 0;
    Node *p = link_list->next;
    while(link_list != p){
        if(count == index){
            p->data = val;
            return;
        }
        p = p->next;
        count++;
    }
    cout<<"修改失败"<<endl;
}
插入节点

分为尾部插入(尾部添加)和中间插入(不包含尾部添加)

//尾部插入
void InsertRear(ListNode &link_list, int val){
    Node *p = link_list;
    while(link_list != p->next){
        p = p->next;
    }
    p->next = new Node(val, link_list);
}

//中间插入
void InsertInside(ListNode &link_list,int index, int val){
    int count = 0;
    Node *p = link_list;
    while(link_list != p->next){
        if(count == index){
            Node *temp = new Node(val, p->next);
            p->next = temp;
            return;
        }
        p = p->next;
        count++;
    }
    cout<<"index超出索引"<<endl;
}
删除节点

因为节点是new出来的,注意注销即可。

void RemoveInside(ListNode &link_list, int index){

    Node *p = link_list;
    int count = 0;
    while(link_list != p->next){
        if(count == index){
            Node* temp = p->next->next;
            delete p->next;
            p->next = temp;
            return;
        }
        p = p->next;
        count++;
    }
    cout << "index 超出索引" << endl;
}
总结

循环链表对比与单链表,它没有指针指向NULL,而是构成了一个圈,但是基本的增删改查相差不大,主要是结束循环的判断条件。

循环链表在某些调度问题上会用到。

对于链表操作,最关键的就是申明一个临时指针去访问链表,这样链表头节点的位置就不会因为增删改查操作而改变。


老规矩,有用,希望能送上你的二连,感谢!

附录

全部代码

#include<iostream>
#include<cstdlib>
#include<vector>

using namespace std;

typedef struct Node{

    int data;
    Node* next;
    Node():data(0),next(this){}; 
    Node(int x, Node *node):data(x),next(node){}; 

}*ListNode;

template<typename T>
void CreateList(ListNode &link_list, T arr, int len){
    Node* p = link_list;
    for(int i=0; i<len; i++){
        p->next = new Node(arr[i], link_list);
        p = p->next;
    }
}

void ShowList(const ListNode &link_list){
    Node* p = link_list->next;
    while(p != link_list){
        cout << p->data << "\t";
        p = p->next;
    }
    cout << endl;
}

Node* FindValue(const ListNode &link_list, int val){
    Node *p = link_list->next;
    while(link_list != p){
        if(p->data == val) return p;
        p = p->next;
    }
    return NULL;
}

Node* FindIndex(const ListNode &link_list, int index){
    Node *p = link_list->next;
    int count = 0;
    while(link_list != p){
        if(count == index) return p;
        p = p->next;
        count++;
    }
    return NULL;
}

void ChangeNode(ListNode &link_list,int index, int val){
    int count = 0;
    Node *p = link_list->next;
    while(link_list != p){
        if(count == index){
            p->data = val;
            return;
        }
        p = p->next;
        count++;
    }
    cout<<"修改失败"<<endl;
}

void InsertRear(ListNode &link_list, int val){
    Node *p = link_list;
    while(link_list != p->next){
        p = p->next;
    }
    p->next = new Node(val, link_list);
}

void InsertInside(ListNode &link_list,int index, int val){
    int count = 0;
    Node *p = link_list;
    while(link_list != p->next){
        if(count == index){
            Node *temp = new Node(val, p->next);
            p->next = temp;
            return;
        }
        p = p->next;
        count++;
    }
    cout<<"index超出索引"<<endl;
}

void RemoveInside(ListNode &link_list, int index){

    Node *p = link_list;
    int count = 0;
    while(link_list != p->next){
        if(count == index){
            Node* temp = p->next->next;
            delete p->next;
            p->next = temp;
            return;
        }
        p = p->next;
        count++;
    }
    cout << "index 超出索引" << endl;
}


int main(){

    ListNode link_list = new Node();

    vector<int> a = {1,2,3,4,5};
    CreateList(link_list, a , a.size());
    ShowList(link_list);

    Node *temp = FindValue(link_list,5);
    cout << temp->data << endl;

    temp = FindValue(link_list,8);
    if(temp == NULL) cout<<"找不到"<<endl;

    temp = FindIndex(link_list,4);
    if(temp == NULL) cout<<"找不到"<<endl;
    else cout << temp->data << endl;

    ChangeNode(link_list, 0, 100);
    ShowList(link_list);

    ChangeNode(link_list, 4, 100);
    ShowList(link_list);

    InsertInside(link_list,0, 1000);
    ShowList(link_list);

    InsertRear(link_list,  10000);
    ShowList(link_list);

    RemoveInside(link_list,0);
    ShowList(link_list);

    RemoveInside(link_list,5);
    ShowList(link_list);

    RemoveInside(link_list,5);
    ShowList(link_list);

    system("pause");
    return 0;
}
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值