c++一种简单的链表写法

首先创建一个带有尾指针的类,写两个构造方法,一个为私有供内部自己使用,另一个用来初始化,id作为模拟的数据,在对象初始化时,对象名将作为头指针,头指针不带有数据,同时将尾(末尾)指针指向自己

class stu{
public:
    stu() {
        this->id = 0;
        this->end = this;
        this->next = nullptr;
        this->length = 0;
    }
    void addItem(int i,int pos);
    void delItem(int pos);
    void pushBack(int i);
    int size() {
        return this->length;
    };
    void show() {
        //由于把this指针作为了头节点,头节点不存放数据
        //同时得益于尾指针的存在,在头插和尾插可以得到更高的效率
        if (this->length == 0) {
            cout << "没有元素" << endl;
            return;
        }
        stu* tmp = this->next;
        while (tmp != nullptr) {
            cout << tmp->id;
            if (tmp->next == nullptr) {
                cout << endl;
            }
            else {
                cout << ",";
            }
            tmp = tmp->next;
        }
    }
private:
    stu* end;
    int length;
    int id;
    stu* next;
    stu(int i) {
        this->length = 1;
        this->id = i;
        this->next = nullptr;
        this->end = this;
    }
};

由于我们有一个尾指针,我们先写一个尾插法,调用私有的构造函数,创建一个新的结点由end->next(this->end->next)来接收,随后将end指针指向新插入的末尾结点,然后长度自增1.

void stu::pushBack(int i){
        end->next = new stu(i);
        end = end->next;
        this->length++;
    }

接着写上普通的插入功能,需要提供数据(i)以及位置(pos),首先判断位置是否合适,不合适直接retrun跳出.

发现是往最尾插入,直接调用尾插法.

发现是往头部插入,首先申请一个新的tmp结点调用私有构造方法填入数据,之后将tmp结点的next指针指向头结点的下一位(next),之后再将头结点的下一位指向tmp,随后长度自增1后跳出.

如果既非头插也非尾插,则申请一个current结点进行一次遍历,遍历时找到指定位置的上一位,如我要插入第三位,那我先将当前(current)的指针指向第二位,随后申请一个新的tmp结点填入数据,再将tmp的下一位(tmp->next)指向current的下一位(current->next,也就是原来的第三位,current目前是第二位),随后再将current的下一位指向tmp,此时的tmp 为插入后的第三位,随后长度自增1.

void stu::addItem(int i,int pos) {
        if (pos < 1 || pos >this->length + 1) {
            cout << "位置应在1-" << this->length + 1 << "之间" << endl;
            return;
        }
        if (pos == this->length + 1) {
        //直接调用尾插法
            this->pushBack(i);
            return;
        }
        if (pos == 1) {
        //头插法
            stu* tmp = new stu(i);
            tmp->next = this->next;
            this-> next = tmp;
            this->length++;
            return;
        }
        stu* current = this;
        for (int j = 1; j < pos; j++) {
            current = current->next;
        }
        stu* tmp = new stu(i);
        tmp->next = current->next;
        current->next = tmp;
        this->length++;
    }

接着是删除某一位置结点,先做简单的判断,不符合规则则直接跳出.

对于这种结构的链表,除了删除头指针以外,其他都需要进行一次遍历,因为end指针要指向最末尾,直接删除他,end依旧需要遍历找到新的最末尾.

删除最后一位时,遍历找到倒数第二个结点,随后将end指针指向倒数第二位,再删除原最后的一位.

删除第一个结点,由于不可先删除,先删除链表结构会断连,因此需要申请一个新的结点去指向第一个结点,随后头指针的下一位指向第二个结点,保持链表连续结构后,再将第一个结点删除.

删除中间的某一位结点时,则是申请一个新的结点(current)去遍历到指定位置的前一位,随后申请一个临时的结点,去指向删除的指定位置,先将指定位置前一位(current)的next指针指向指定位置的后一位(current->next = tmp->next),保持链表结构不断,再将指定位置结点删除.

void std::delItem(int pos) {
        if (this->length == 0) {
            return;
        }
        if (pos <1 || pos >this->length) {
            cout << "位置应在1-" << this->length << "之间" << endl;
            return;
        }
        if (pos == this->length) {
            stu* tmp = this;
            while (tmp->next->next != nullptr) {
                tmp = tmp->next;
            }
            this->end = tmp;
            delete tmp->next;
            tmp->next = nullptr; 
            this->length--;
            return;
        }
        if (pos == 1) {
            stu* tmp = this->next;
            this->next = tmp->next;
            delete tmp;
            tmp = nullptr;
            this->length--;
            return;
        }
        stu* current = this;
        for (int j = 1; j < pos; j++) {
            current = current->next;
        }
        stu* tmp = current->next;//这个位置是要删除的结点
        current->next = tmp->next;
        delete tmp;
        tmp = nullptr;
        this->length--;
    }

值得注意的是,在删除链表时,切记不可先删除,应该申请一个新的结点先指向,最后把位置都连上后,再将指定位置删除,而在使用delete删除后,还需将申请的对象指向空指针,而如果想直接清空链表,则需要从位指针开始反向遍历,挨个删除.

最后是一个简单的测试

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值