zoukankan      html  css  js  c++  java
  • leetCode书房之链表(LC实现链表)

    1. 单链表实现方案

    这里的插入删除都是在该index的前面操作的,而我们知道一般的链表的话,执行的是一个在当前节点的位置后面进行的操作,
    因为一旦在之前执行,单向链表意味着我们可能需要遍历前面的位置来访问该元素,非常麻烦,这个时候有两个解决方案:

    1. 虚拟头结点
    2. 双向链表
      这里尚且不涉及到双向链表,所以我们采用虚拟头结点:需要在题目给的结构里面在即定义一些新的内容,方便我们操作:

    代码和注释方案

    #include<iostream>
    using namespace std;
    // Definition for singly-linked list.
    class MyLinkedList {
    public:
        // 定义链表节点结构体
        struct LinkedNode {
            int val;
            LinkedNode* next;
            LinkedNode(int val):val(val), next(nullptr){}
        };
    
        // 初始化链表
        MyLinkedList() {
            _dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
            _size = 0;
        }
    
        // 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
        int get(int index) {
            if (index > (_size - 1) || index < 0) {
                return -1;
            }
            LinkedNode* cur = _dummyHead->next;
            while(index--){ // 如果--index 就会陷入死循环
                cur = cur->next;
            }
            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++;
        }
    
        // 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
        // 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
        // 如果index大于链表的长度,则返回空
        void addAtIndex(int index, int val) {
            if (index > _size) {
                return;
            }
            LinkedNode* newNode = new LinkedNode(val);
            LinkedNode* cur = _dummyHead;
            while(index--) {
                cur = cur->next;
            }
            newNode->next = cur->next;
            cur->next = newNode;
            _size++;
        }
    
        // 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
        void deleteAtIndex(int index) {
            if (index >= _size || index < 0) {
                return;
            }
            LinkedNode* cur = _dummyHead;
            while(index--) {
                cur = cur ->next;
            }
            LinkedNode* tmp = cur->next;
            cur->next = cur->next->next;
            delete tmp;
            _size--;
        }
    
        // 打印链表
        void printLinkedList() {
            LinkedNode* cur = _dummyHead;
            while (cur->next != nullptr) {
                cout << cur->next->val << " ";
                cur = cur->next;
            }
            cout << endl;
        }
    private:
        int _size;
        LinkedNode* _dummyHead;
    
    };
    /**
     * Your MyLinkedList object will be instantiated and called as such:
     * MyLinkedList* obj = new MyLinkedList();
     * int param_1 = obj->get(index);
     * obj->addAtHead(val);
     * obj->addAtTail(val);
     * obj->addAtIndex(index,val);
     * obj->deleteAtIndex(index);
     */
    int main()
    {
        MyLinkedList *linkedList = new MyLinkedList();
        linkedList->addAtHead(1);
        linkedList->addAtTail(3);
        linkedList->addAtIndex(1,2);   //链表变为1-> 2-> 3
        linkedList->printLinkedList(); 
        linkedList->get(1); 
    	linkedList->printLinkedList();           //返回2
        linkedList->deleteAtIndex(1);  //现在链表是1-> 3
        linkedList->printLinkedList();
        linkedList->get(1);
    ;            //返回3
        return 0;
    }
    

    2.双向链表的实现

    思路

    双向链表的操作在比起单链表的时候会快很多,大大缩减了访问效率,我们可以利用该数据结构完成很多事,双链表在实现上面也不同于单链表,结构更加复杂,一些访问特性时间复杂度大幅度降低,我们为了方便每个节点之间的一致性,还是需要设置一个头节点head和虚拟尾节点tail

    代码

    #include<iostream>
    using namespace std;
    class MyLinkedList {
    public:
        typedef struct ListNode{
            int val;
            ListNode *next,*prev;
            ListNode(int val):val(val),next(nullptr),prev(nullptr){}
        }Node;
        /** Initialize your data structure here. */
        MyLinkedList() {
            head = new Node(0);
            tail = new Node(0);
            head->next = tail;
            tail->prev = head;
            _size = 0;
        }
        
        /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
        int get(int index) {
            if(index < 0 || index >_size-1){
                return -1;
            }
            Node *cur = head->next;
            while(index--){
                cur = cur->next;
            }
            return cur->val;
        }
        
        /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
        void addAtHead(int val) {
            Node *pred = head;
            Node *succ = head->next;
            Node *new_item = new Node(val);
            new_item->next = succ;
            new_item->prev = pred;
            pred->next = new_item;
            succ->prev = new_item; 
            _size++;
        }
        
        /** Append a node of value val to the last element of the linked list. */
        void addAtTail(int val) {
            Node *pred = tail->prev;
            Node *succ = tail;
            Node *new_item = new Node(val);
            new_item->next = succ;
            new_item->prev = pred;
            pred->next = new_item;
            succ->prev = new_item;
            _size++;
        }
        
        /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
        void addAtIndex(int index, int val) {
            if (index > _size) 
                return;
            if(index < 0) index = 0;
            Node *pred,*succ;
            if (index < _size - index) {
                pred = head;
                for(int i = 0; i < index; ++i) pred = pred->next;
                succ = pred->next;
            }
            else {
                succ = tail;
                for (int i = 0; i < _size - index; ++i) succ = succ->prev;
                pred = succ->prev;
            }
            // insertion itself
            ++_size;
            Node *toAdd = new Node(val);
            toAdd->prev = pred;
            toAdd->next = succ;
            pred->next = toAdd;
            succ->prev = toAdd;
        }
        
        /** Delete the index-th node in the linked list, if the index is valid. */
        void deleteAtIndex(int index) {
            if(index >= _size || index < 0)
                return;
            Node *pred,*succ;
            if (index < _size - index) {
                pred = head;
                for(int i = 0; i < index; ++i) pred = pred->next;
                succ = pred->next->next;
            }
            else {
                succ = tail;
                for (int i = 0; i < _size - index-1; ++i) succ = succ->prev;//
                pred = succ->prev->prev;
            }
            --_size;
            pred->next = succ;
            succ->prev = pred;
        }
        void printLinkedList() {
            Node* cur = head;
            while (cur->next != nullptr && cur->next != tail) {
                cout << cur->next->val << " ";
                cur = cur->next;
            }
            cout << endl;
        }
    private:
        Node * head,*tail;
        int _size;
    };
    
    /**
     * Your MyLinkedList object will be instantiated and called as such:
     * MyLinkedList* obj = new MyLinkedList();
     * int param_1 = obj->get(index);
     * obj->addAtHead(val);
     * obj->addAtTail(val);
     * obj->addAtIndex(index,val);
     * obj->deleteAtIndex(index);
     */
    int main()
    {
        MyLinkedList *linkedList = new MyLinkedList();
        linkedList->addAtHead(1);
        linkedList->addAtTail(3);
        linkedList->addAtIndex(1,2);   //链表变为1-> 2-> 3
        linkedList->printLinkedList(); 
        linkedList->get(1); 
    	linkedList->printLinkedList();           //返回2
        linkedList->deleteAtIndex(1);  //现在链表是1-> 3
        linkedList->printLinkedList();
        linkedList->get(1);
                //返回3
        return 0;
    }
    

    3. 总结

    单向链表的实现依据不同的需求有不同的方法,但是单链表的查找会变得很麻烦,需要的平均世家复杂度更加高,双链表的访问速度有所提高,一般来说的话,是单链表的两倍,主要是因为访问的某个节点的前一个节点的时候,我们不需要遍历链表了,访问可以借助指针在(O(1))时间内完成。

    抬起头,永远年轻,永远热泪盈眶!
  • 相关阅读:
    112th LeetCode Weekly Contest Validate Stack Sequences
    112th LeetCode Weekly Contest Minimum Increment to Make Array Unique
    C# 有关系统音量的操作
    C# 关于时区的操作
    WordPress 设置GeoIP数据库目录权限时错误解决方案
    AtCoder Beginner Contest 113 C
    AtCoder Beginner Contest 113 B
    AtCoder Beginner Contest 113 A
    将Tomcat注册为Windows服务
    常用的调试方法
  • 原文地址:https://www.cnblogs.com/marvin-Hua-manlou/p/13882286.html
Copyright © 2011-2022 走看看