链表-双链表的设计

博客探讨了力扣中index的范围起始问题。力扣参考答案注释显示,若index为负数,节点添加在列表开头且index设为0,addAtIndex(0,val)表示在第0个节点前添加节点,说明index从0开始,而size从1开始。还提及了代码部分只写了添加指定位置值的内容。

一、问题

1、index的范围究竟从1开始还是从0开始?

  /** 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. */
  public void addAtIndex(int index, int val) {
    // If index is greater than the length, 
    // the node will not be inserted.
    if (index > size) return;

    // [so weird] If index is negative, 
    // the node will be inserted at the head of the list.
    if (index < 0) index = 0;
	// 余下代码省略

在力扣参考答案中有这样的注释——如果index为负数,那么节点将添加在列表开头,index设置为0,也就是说,在第0个节点之前添加节点的函数调用是addAtIndex(0,val);
在这个函数的开头注释说明中写道,将一个节点添加到第index-th节点之前,也就是说index是从0开始的,index为0是有效的,我们应该说是第0个节点
size和index不同,size是从1开始的;

二、代码部分(自己只写了添加指定位置的值的部分)

class ListNode {
    int val;
    ListNode next;
    ListNode prev;
    ListNode(int x) { val = x; }
}

class MyLinkedList {
    int size;
    // sentinel nodes as pseudo-head and pseudo-tail
    ListNode head, tail;
    public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
        tail = new ListNode(0);
        head.next = tail;
        tail.prev = head;
    }

    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    public int get(int index) {
        // if index is invalid
        if (index < 0 || index >= size) return -1;

        // choose the fastest way: to move from the head
        // or to move from the tail
        ListNode curr = head;
        if (index + 1 < size - index)
            for(int i = 0; i < index + 1; ++i) curr = curr.next;
        else {
            curr = tail;
            for(int i = 0; i < size - index; ++i) curr = curr.prev;
        }

        return curr.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. */
    public void addAtHead(int val) {
        ListNode pred = head, succ = head.next;

        ++size;
        ListNode toAdd = new ListNode(val);
        toAdd.prev = pred;
        toAdd.next = succ;
        pred.next = toAdd;
        succ.prev = toAdd;
    }

    /** Append a node of value val to the last element of the linked list. */
    public void addAtTail(int val) {
        ListNode succ = tail, pred = tail.prev;

        ++size;
        ListNode toAdd = new ListNode(val);
        toAdd.prev = pred;
        toAdd.next = succ;
        pred.next = toAdd;
        succ.prev = toAdd;
    }

    /** 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. */
    public void addAtIndex(int index, int val) {
        // If index equals to the length of linked list, the node will be appended to the end of linked list.
        // 根据这句话:在(index-1)th的节点后加节点
        if(index < 0 || index > size)return;

//        ListNode cur = head;
//        ListNode newNode = new ListNode(val);
//        for (int i = 0; i < size; i++) {
//            cur = cur.next;
//        }
//        cur.next = newNode;
//        newNode.prev = cur;
        ListNode newNode = new ListNode(val);
        ListNode pred, succ;
        if(index * 2 < size){
            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 - 1; i++) {
                succ = succ.prev;
            }
            pred = succ.prev;
        }
        pred.next = newNode;
        newNode.prev = pred;
        newNode.next = succ;
        succ.prev = newNode;
        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. */
//    public void addAtIndex(int index, int val) {
//        // If index is greater than the length,
//        // the node will not be inserted.
//        if (index > size) return;
//
//        // [so weird] If index is negative,
//        // the node will be inserted at the head of the list.
//        if (index < 0) index = 0;
//
//        // find predecessor and successor of the node to be added
//        ListNode 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;
//        ListNode toAdd = new ListNode(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. */
    public void deleteAtIndex(int index) {
        // if the index is invalid, do nothing
        if (index < 0 || index >= size) return;

        // find predecessor and successor of the node to be deleted
        ListNode 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;
        }

        // delete pred.next
        --size;
        pred.next = succ;
        succ.prev = pred;
    }
}

class test{
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addAtHead(0);
        list.addAtHead(1);
        list.addAtHead(2);
        list.addAtIndex(0,3);
        for (int i = 0; i < list.size; i++) {
            System.out.println(list.get(i));
        }
    }
}

以下是针对红黑树扩展 `find` 函数的详细实现方案,包含多种查找需求(精确查找、范围查找、前驱/后继查找)及测试用例: --- ### **一、基础精确查找** #### 1. 函数实现 ```cpp template<class KEY, class VALUE> class RBTree { public: // 精确查找(返回节点指针,未找到返回nullptr) RBTreeNode<KEY, VALUE>* find(const KEY& key) const { RBTreeNode<KEY, VALUE>* current = m_pRoot; while (current && !current->isNIL()) { if (key == current->m_Key) { return current; } else if (key < current->m_Key) { current = current->m_pLeft; } else { current = current->m_pRight; } } return nullptr; } // 重载:返回键值对(C++17结构化绑定友好) std::optional<std::pair<const KEY&, VALUE&>> find_pair(const KEY& key) { auto node = find(key); if (node) { return std::make_pair(std::ref(node->m_Key), std::ref(node->m_Value)); } return std::nullopt; } }; ``` #### 2. 测试用例 ```cpp TEST_CASE("Exact Find") { RBTREE::RBTree<int, std::string> tree; tree.Insert(10, "ten"); tree.Insert(20, "twenty"); SUBCASE("Existing Key") { auto node = tree.find(10); CHECK(node != nullptr); CHECK(node->m_Value == "ten"); } SUBCASE("Non-existing Key") { CHECK(tree.find(15) == nullptr); } SUBCASE("Find Pair") { auto result = tree.find_pair(20); CHECK(result.has_value()); CHECK(result->first == 20); CHECK(result->second == "twenty"); } } ``` --- ### **二、范围查找** #### 1. 函数实现 ```cpp // 返回[min_key, max_key]范围内的所有键值对 std::vector<std::pair<KEY, VALUE>> find_range(const KEY& min_key, const KEY& max_key) const { std::vector<std::pair<KEY, VALUE>> result; std::stack<RBTreeNode<KEY, VALUE>*> stack; RBTreeNode<KEY, VALUE>* current = m_pRoot; // 中序遍历+范围过滤 while (!stack.empty() || (current && !current->isNIL())) { if (current && !current->isNIL()) { stack.push(current); current = current->m_pLeft; } else { current = stack.top(); stack.pop(); if (current->m_Key >= min_key && current->m_Key <= max_key) { result.emplace_back(current->m_Key, current->m_Value); } else if (current->m_Key > max_key) { break; // 提前终止 } current = current->m_pRight; } } return result; } ``` #### 2. 测试用例 ```cpp TEST_CASE("Range Find") { RBTREE::RBTree<int, std::string> tree; for (int i = 1; i <= 10; ++i) { tree.Insert(i, std::to_string(i)); } SUBCASE("Normal Range") { auto range = tree.find_range(3, 7); CHECK(range.size() == 5); CHECK(range.front().first == 3); CHECK(range.back().first == 7); } SUBCASE("Open Range") { auto range = tree.find_range(8, 15); CHECK(range.size() == 3); // 8,9,10 } SUBCASE("Empty Range") { CHECK(tree.find_range(15, 20).empty()); } } ``` --- ### **三、前驱/后继查找** #### 1. 函数实现 ```cpp // 查找键的前驱节点(小于key的最大键) RBTreeNode<KEY, VALUE>* find_predecessor(const KEY& key) const { RBTreeNode<KEY, VALUE>* current = m_pRoot; RBTreeNode<KEY, VALUE>* predecessor = nullptr; while (current && !current->isNIL()) { if (key > current->m_Key) { predecessor = current; current = current->m_pRight; } else { current = current->m_pLeft; } } return predecessor; } // 查找键的后继节点(大于key的最小键) RBTreeNode<KEY, VALUE>* find_successor(const KEY& key) const { RBTreeNode<KEY, VALUE>* current = m_pRoot; RBTreeNode<KEY, VALUE>* successor = nullptr; while (current && !current->isNIL()) { if (key < current->m_Key) { successor = current; current = current->m_pLeft; } else { current = current->m_pRight; } } return successor; } ``` #### 2. 测试用例 ```cpp TEST_CASE("Predecessor/Successor") { RBTREE::RBTree<int, std::string> tree; tree.Insert(10, "ten"); tree.Insert(20, "twenty"); tree.Insert(5, "five"); tree.Insert(15, "fifteen"); SUBCASE("Predecessor") { auto pred = tree.find_predecessor(15); CHECK(pred != nullptr); CHECK(pred->m_Key == 10); } SUBCASE("Successor") { auto succ = tree.find_successor(10); CHECK(succ != nullptr); CHECK(succ->m_Key == 15); } SUBCASE("Edge Cases") { CHECK(tree.find_predecessor(5) == nullptr); // 最小键无前驱 CHECK(tree.find_successor(20) == nullptr); // 最大键无后继 } } ``` --- ### **四、模糊查找(扩展功能)** #### 1. 函数实现(基于比较函数) ```cpp template<typename CompareFunc> RBTreeNode<KEY, VALUE>* find_if(CompareFunc comp) const { std::stack<RBTreeNode<KEY, VALUE>*> stack; RBTreeNode<KEY, VALUE>* current = m_pRoot; while (!stack.empty() || (current && !current->isNIL())) { if (current && !current->isNIL()) { stack.push(current); current = current->m_pLeft; } else { current = stack.top(); stack.pop(); if (comp(*current)) { return current; // 返回第一个满足条件的节点 } current = current->m_pRight; } } return nullptr; } // 示例:查找第一个值大于10的节点 auto node = tree.find_if([](const auto& n) { return n.m_Value > "10"; }); ``` #### 2. 测试用例 ```cpp TEST_CASE("Custom Find") { RBTREE::RBTree<int, std::string> tree; tree.Insert(1, "A"); tree.Insert(2, "BB"); tree.Insert(3, "CCC"); auto node = tree.find_if([](const auto& n) { return n.m_Value.length() > 1; }); CHECK(node != nullptr); CHECK(node->m_Key == 2); } ``` --- ### **五、性能优化建议** 1. **迭代器缓存**: ```cpp // 在RBTree类中添加缓存 mutable RBTreeNode<KEY, VALUE>* m_pLastFind = nullptr; // 优化后的find RBTreeNode<KEY, VALUE>* find(const KEY& key) const { if (m_pLastFind && m_pLastFind->m_Key == key) { return m_pLastFind; } // ...原有查找逻辑 m_pLastFind = result; // 缓存结果 return result; } ``` 2. **范围查找优化**: - 对有序数据使用二分搜索思想跳过不可能的子树 3. **多线程安全**: ```cpp // 线程安全版本(使用原子操作) std::atomic<RBTreeNode<KEY, VALUE>*> m_pLastFind; ``` --- ### **六、错误处理增强** 1. **异常安全**: ```cpp VALUE& at(const KEY& key) { auto node = find(key); if (!node) throw std::out_of_range("Key not found"); return node->m_Value; } ``` 2. **日志记录**: ```cpp #ifdef DEBUG_FIND #define LOG_FIND(key, result) std::cout << "Find " << key << ": " << (result ? "Hit" : "Miss") << "\n" #else #define LOG_FIND(key, result) #endif RBTreeNode<KEY, VALUE>* find(const KEY& key) const { // ...查找逻辑 LOG_FIND(key, result); return result; } ``` --- ### **七、完整测试套件** ```cpp TEST_SUITE("Find Operations") { RBTREE::RBTree<int, std::string> tree; TEST_CASE_FIXTURE(SetupFixture) { tree.Insert(10, "ten"); tree.Insert(20, "twenty"); tree.Insert(5, "five"); } TEST_CASE("All Find Methods") { CHECK(tree.find(10)->m_Value == "ten"); CHECK(tree.find_range(5, 20).size() == 3); CHECK(tree.find_predecessor(10)->m_Key == 5); CHECK(tree.find_successor(10)->m_Key == 20); } TEST_CASE("Performance") { for (int i = 0; i < 10000; ++i) { tree.Insert(i, std::to_string(i)); } auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < 10000; i += 100) { CHECK(tree.find(i) != nullptr); } auto duration = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::high_resolution_clock::now() - start); CHECK(duration.count() < 10); // 阈值根据硬件调整 } } ``` --- ### **
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值