一、链表笔记

口诀:插入先连后再前,删除留前连后后;
(插入的时候需要先连后面,把原本的下一个cur->next给newnode->next,再更新cur->next为newnode; 删除的时候cur是删除位置index的前一个,删的是cur->next,这样才能把后后的cur->next->next连到cur上,最后delete完手动nullptr一下指针。)
**遍历时得由一个新指针 cur,不然head遍历完找不回头了。
**
**if不同条件是需要else,否则可能前一个If执行出来后又满足后一个If的条件;小心两个分类中交叉的边界条件 n=0 n =_size-1 **

链表节点定义

//节点数据可以是多种类型,这里设置成int
typedef int datatype;
struct ListedNode{
	datatype val;
	struct ListedNode* next;//指针变量,放的是地址
	ListedNode(int x):val(x), nextnext(nullptr){}
	};//用来定义新结点

一、单链表

1、打印
在遍历链表的时候需要一个新指针来遍历,不用头指针是因为如果用head,遍历完成之后head指向最后一个了,就找不着这个链表了,所以需要一个新指针

void printLinkedList(){
        LinkedNode* cur = _dummyhead->next;
        while(cur != nullptr){
            cout<< cur->val<<"->";
            cur = cur->next;
        }
        cout<<endl;
    }

2、插入
(1)插尾


   //插尾
    void addAtTail(int val) {
        LinkedNode* newnode = new LinkedNode(val);
        LinkedNode* cur = _dummyhead;
        while(cur->next){
            cur= cur->next;
        }
        cur->next = newnode;
        _size++;
    }
}

理解:newnode是指向新结点的指针变量,他存放的内容是地址,和指向新结点的cur一样的地址
(2)插头
插入时,先连接后,再连接前,用到了长度,添加节点长度也发送变化

//插头
    //**插入时,先连接后,再连接前
    void addAtHead(int val) {
        LinkedNode* newnode = new LinkedNode(val);
        newnode->next = _dummyhead->next;
        _dummyhead->next = newnode;
        //**用到了长度,添加节点长度也发送变化
        _size++;
    }

(3)第n个位置

3、删除
时间复杂度: O(n)
空间复杂度: O(1)
需要删除掉delete这个结点,
如果有指针指向删除掉的节点,该指针也要=NULL否则就是悬空指针(指向的地址内存不在了)
前提是head非空,由于删头和删中间不同(删头需要更新并返回头结点),所以构造虚拟头结点,不需要考虑空,头或尾,用完删除虚拟头结点即可。
1、删头,删非头

ListNode* removeElement(ListNode* head, int val) {
        while(head != NULL && head->val == val){//删头 小心是while
            ListNode* cur = head;
            head = head->next;
            delete cur;
        }
        
        //删非头
        ListNode* cur = head;
        whille(cur! = NULL && cur->next != NULL){ //**头结点非空
            if(head->next->val == val){
                //**必须先搞个指针暂放,不然先连接前后,要删的cur-next就找不到了
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;//此时无需更新next因为已经变成新的了
            }
            else{
                cur = cur->next;
            }
            
            
        }
        return head;
    }

2、虚拟头结点
通用版,设置虚拟头节点

ListNode* removeElement(ListNode* head, int val) {
        ListNode* dummyhead = new ListNode(0);//虚拟头结点
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        while(cur->next != NULL){
            //由于删除一个是前后两个相连,所以cur保留,看next空不空
            if(cur->next->val == val){
                ListNode* tmp =cur->next;//要删的
                cur->next = cur->next->next;
                delete tmp;//删除指针以及指针指向的结点
            }
        }
        //每一个都检查到了,删除虚拟头结点
        head = dummyhead->next;//新头结点的地址
        delete dummyhead;
        return  head;
    }

获取第n个节点(查找)
小心边界,看是n是从0 开始还是从1开始
在这里插入图片描述为什么是_
_size 作为变量名时,前面的下划线 _ 是一种常见的命名约定,用于表示该变量是一个类的成员变量

class MyLinkedList {
public:
    //定义
    struct LinkedNode{
        int val;
        LinkedNode* next;
        LinkedNode(int x) : val(x), next(nullptr){}
    };
    //初始化
    MyLinkedList() {
        _dummyhead = new LinkedNode(0);
        _size = 0;
    }
    //获取节点值
    int get(int index) {
        //下标0~size-1,无效返回-1
        if(index < 0 || index >_size-1){
            return -1;
        }
        //找到第n个,从前往后n~第0个
        LinkedNode* cur = _dummyhead->next;//所以这里是原本第0个
        while(index--){
            cur = cur->next;
        }
        //第0个不进入后移循环,所以
        return cur->val;
        
    }
    
    //插头
    //**插入时,先连接后,再连接前
    void addAtHead(int val) {
        LinkedNode* newnode = new LinkedNode(val);
        newnode->next = _dummyhead->next;
        _dummyhead->next = newnode;
        //**用到了长度,添加节点长度也发送变化
        _size++;
        
    }
    
    //插尾
    void addAtTail(int val) {
        LinkedNode* newnode = new LinkedNode(val);
        LinkedNode* cur = _dummyhead;
        while(cur->next!=nullptr){
            cur= cur->next;
        }
        cur->next = newnode;
        _size++;
        
    }
    
    //插中间,需要前一个
    void addAtIndex(int index, int val) {
        if(index == _size){
            addAtTail(val);
        }
        //**这里index>=0,如果有小于0就得再来一个if 重给 index = 0
        else if(index >=0 && index < _size){
            LinkedNode* newnode = new LinkedNode(val);
            LinkedNode* cur = _dummyhead;
            while(index--){
                cur = cur->next;
           }
           //要插入的是cur->next
           newnode->next = cur->next;//**还没给呐,
           cur->next = newnode;
           _size++;
        }
        
       
       
    }
    
    //删除第N个,得找到前一个(删的是cur->next)
    void deleteAtIndex(int index) {
        //下标有效才删除
        if(index <0 || index >_size-1) return;
        LinkedNode* cur = _dummyhead;
        //**得保留前一个
        while(index--){
            cur = cur->next; //**此时cur是index前面一个
            
        }
        LinkedNode* tmp = cur->next;
        cur->next = cur-> next->next;
        delete tmp;//释放了tmp内容,但是非空,值随机
        tmp = nullptr;//空指针
        //**size变了
        _size--;
       
    }
    
    void printLinkedList(){
        LinkedNode* cur = _dummyhead->next;
        while(cur != nullptr){
            cout<< cur->val<<"->";
            cur = cur->next;
        }
        cout<<endl;
    }
    
private:
    int _size;
    LinkedNode* _dummyhead; //只可以在类内部被访问
};

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值