简单练习2

218 阅读7分钟

二叉树层序遍历结果

#include <iostream>  
#include <queue>  
#include <vector>  
  
// 定义二叉树节点结构  
struct TreeNode
{  
    int val;  
    TreeNode *left;  
    TreeNode *right;  
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}  
};    
  
  void levelOrderTraverse(TreeNode* root)
{
    if (root == nullptr)
    {
        return;
    }
    queue<TreeNode*> q;
    q.push(root);
    // 记录当前遍历到的层数(根节点视为第 1 层)
    int depth = 1;

    while (!q.empty())
    {
        int sz = q.size();
        for (int i = 0; i < sz; i++)
        {
            TreeNode* cur = q.front();
            q.pop();
            // 访问 cur 节点,同时知道它所在的层数
            cout << "depth = " << depth << ", val = " << cur->val << endl;

            // 把 cur 的左右子节点加入队列
            if (cur->left != nullptr)
            {
                q.push(cur->left);
            }
            if (cur->right != nullptr)
            {
                q.push(cur->right);
            }
        }
        depth++;
    }
}
  
  
int main() {  
    // 构建一棵测试用的二叉树  
    //        1  
    //       / \  
    //      2   3  
    //     / \   \  
    //    4   5   6  
    TreeNode* root = new TreeNode(1);  
    root->left = new TreeNode(2);  
    root->right = new TreeNode(3);  
    root->left->left = new TreeNode(4);  
    root->left->right = new TreeNode(5);  
    root->right->right = new TreeNode(6);  
  
    // 执行层序遍历,并获取结果  
    std::vector<int> result = levelOrderTraversal(root);  
  
    // 输出结果  
    for (int val : result)
    {  
        std::cout << val << " ";  
    }  
    std::cout << std::endl;  
  
    // 注意:这里省略了释放分配的内存的代码  
    // 实际使用中,应当在适当的位置释放这些内存以避免内存泄漏  
  
    return 0;  
}

二叉树非递归遍历

前序遍历

void preorderTraversal(TreeNode* root) {
    if (root == nullptr) return;
 
    std::stack<TreeNode*> stk;
    stk.push(root);
 
    while (!stk.empty()) {
        TreeNode* node = stk.top();
        stk.pop();
 
        // 访问节点
        std::cout << node->val << " ";
 
        // 注意:这里要先压入右子节点,再压入左子节点,
        // 因为栈是后进先出,而我们希望先遍历左子树
        if (node->right) stk.push(node->right);
        if (node->left) stk.push(node->left);
    }
}

中序遍历

void inorderTraversal(TreeNode* root) 
{
    std::stack<TreeNode*> stk;
    TreeNode* curr = root;

    while (curr != nullptr || !stk.empty())
    {
        // 遍历左子树,将左子节点依次入栈
        while (curr != nullptr)
        {
            stk.push(curr);
            curr = curr->left;
        }

        // 栈顶元素即为当前子树的最左节点,处理它
        curr = stk.top();
        stk.pop();
        std::cout << curr->val << " ";  // 访问节点

        // 转向右子树
        curr = curr->right;
    }
}

后序遍历

void postorderTraversal(TreeNode* root) {
    if (root == nullptr) return;
 
    std::stack<TreeNode*> stk1, stk2; // 使用两个栈
    stk1.push(root);
 
    while (!stk1.empty()) {
        TreeNode* node = stk1.top();
        stk1.pop();
        stk2.push(node); // 将节点压入第二个栈
 
        // 先压入右子节点,再压入左子节点(因为栈是后进先出)
        if (node->left) stk1.push(node->left);
        if (node->right) stk1.push(node->right);
    }
 
    // 第二个栈中的节点顺序就是后序遍历的顺序
    while (!stk2.empty()) {
        TreeNode* node = stk2.top();
        stk2.pop();
        std::cout << node->val << " ";
    }
}

链表是否包含环

class Solution
{
public:
    ListNode* detectCycle(ListNode* head)
    {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != nullptr && fast->next != nullptr)
        {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)
                break;
        }
        // 上面的代码类似 hasCycle 函数
        if (fast == nullptr || fast->next == nullptr)
        {
            // fast 遇到空指针说明没有环
            return nullptr;
        }

        // 重新指向头结点
        slow = head;
        // 快慢指针同步前进,相交点就是环起点
        while (slow != fast)
        {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

反转链表

// 定义链表节点结构体  
struct ListNode
{  
    int val;  
    ListNode* next;  
    ListNode(int x) : val(x), next(nullptr) {}  
};  
  
// 反转单链表的函数  
ListNode* reverseList(ListNode* head)
{  
    ListNode* prev = nullptr; // 前一个节点,初始化为nullptr  
    ListNode* curr = head;    // 当前节点,初始化为头节点  
    ListNode* next = nullptr; // 下一个节点,用于临时存储当前节点的下一个节点  
  
    while (curr != nullptr)
    {  
        // 临时存储当前节点的下一个节点  
        next = curr->next;  
        // 将当前节点的next指针指向前一个节点  
        curr->next = prev;  
        // 移动前一个节点和当前节点到下一个位置  
        prev = curr;  
        curr = next;  
    }  
  
    // 当循环结束时,prev将指向新的头节点(原链表的尾节点)  
    return prev;  
}  
/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param m int整型 
     * @param n int整型 
     * @return ListNode类
     */
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        // write code here
       
        auto dummy = new ListNode(0);
        dummy->next = head;

        ListNode* preNode = dummy;
        ListNode* curNode = head;

        for (int i = 1; i < m; i++)
        {
            preNode = curNode;
            curNode = curNode->next;
        }

        ListNode* next = nullptr;
        for (int j = 0; j < n - m; j++)
        {
            next = curNode->next;
            curNode->next = next->next;
            next->next = preNode->next;
            preNode->next = next;
        }

        return dummy->next;
    }
};

209. 长度最小的子数组 - 力扣(LeetCode)

class Solution 
{
public:
    int minSubArrayLen(int target, vector<int>& nums)
    {
        int result = INT32_MAX, left = 0, right = 0, curentSum = 0;
        while(right < nums.size())
        {
            curentSum += nums[right];
            while (curentSum >= target)
            {
                result = min(result, right - left +1);
                curentSum -= nums[left++];
            }
            right++;
        }
        return result == INT32_MAX ? 0 : result;
    }
};

字符串是否有效

给定一个只包括'('')''{''}''['']' 的字符串s,判断字符串是否有效。

#include <stack>  
#include <string>  
  
bool isValid(const std::string& s)
{  
    std::stack<char> stk;  
  
    for (char c : s)
    {  
        if (c == '(' || c == '[' || c == '{')
        {  
            stk.push(c);  
        }
        else if (c == ')' || c == ']' || c == '}')
        {  
            if (stk.empty())
            {  
                return false; // 没有对应的左括号  
            }  
            char top = stk.top();  
            stk.pop();  
            if ((c == ')' && top != '(') ||  
                (c == ']' && top != '[') ||  
                (c == '}' && top != '{'))
            {  
                return false; // 左右括号不匹配  
            }  
        }  
    }  
  
    return stk.empty(); // 如果栈为空,则所有括号都匹配  
}  

删除元素

// 函数模板,用于从vector中删除所有等于value的元素  
template <typename T>  
void remove_value_without_remove(std::vector<T>& vec, const T& value)
{  
    auto it = vec.begin();  
    while (it != vec.end())
    {  
        if (*it == value)
        {  
            it = vec.erase(it); // 如果找到值,则erase并更新迭代器  
        }
        else
        {  
            ++it; // 否则,继续遍历  
        }  
    }  
}  

智能指针

#include <iostream>
#include <atomic>

// 控制块类,用于管理引用计数和对象
template <typename T>
class ControlBlock
{
public:
    std::atomic<int> ref_count; // 引用计数
    T* object_ptr;              // 指向被管理的对象

    explicit ControlBlock(T* obj) : ref_count(1), object_ptr(obj) {}

    void add_ref()
    {
        ++ref_count;
    }

    void release()
    {
        if (--ref_count == 0)
        {
            // 引用计数为零,释放对象和控制块
            delete object_ptr;
            delete this;
        }
    }
};

// 智能指针类
template <typename T>
class MySharedPtr
{
private:
    T* ptr;
    ControlBlock<T>* control_block;

public:
    // 构造函数
    explicit MySharedPtr(T* p = nullptr)
        : ptr(p), control_block(p ? new ControlBlock<T>(p) : nullptr) {}

    // 拷贝构造函数
    MySharedPtr(const MySharedPtr& other)
        : ptr(other.ptr), control_block(other.control_block)
    {
        if (control_block)
        {
            control_block->add_ref();
        }
    }

    // 移动构造函数
    MySharedPtr(MySharedPtr&& other) noexcept
        : ptr(other.ptr), control_block(other.control_block)
    {
        other.ptr = nullptr;
        other.control_block = nullptr;
    }

    // 拷贝赋值运算符
    MySharedPtr& operator=(const MySharedPtr& other)
    {
        if (this != &other)
        {
            release(); // 释放当前对象
            ptr = other.ptr;
            control_block = other.control_block;
            if (control_block)
            {
                control_block->add_ref();
            }
        }
        return *this;
    }

    // 移动赋值运算符
    MySharedPtr& operator=(MySharedPtr&& other) noexcept
    {
        if (this != &other)
        {
            release(); // 释放当前对象
            ptr = other.ptr;
            control_block = other.control_block;
            other.ptr = nullptr;
            other.control_block = nullptr;
        }
        return *this;
    }

    // 析构函数
    ~MySharedPtr()
    {
        release();
    }

    // 获取原始指针
    T* get() const
    {
        return ptr;
    }

    // 重载解引用运算符
    T& operator*() const
    {
        return *ptr;
    }

    // 重载箭头运算符
    T* operator->() const
    {
        return ptr;
    }

    // 获取引用计数(可选,用于调试)
    int use_count() const
    {
        return control_block ? control_block->ref_count : 0;
    }

private:
    void release()
    {
        if (control_block)
        {
            control_block->release();
            ptr = nullptr;
            control_block = nullptr;
        }
    }
};

// 示例使用
int main()
{
    MySharedPtr<int> sp1(new int(10));
    {
        MySharedPtr<int> sp2 = sp1; // 共享所有权
        std::cout << "sp2 value: " << *sp2 << ", use_count: " << sp2.use_count() << std::endl;
    } // sp2 离开作用域,但引用计数不为0,因此不会释放资源(由sp1维持)

    std::cout << "sp1 value after sp2 out of scope: " << *sp1 << ", use_count: " << sp1.use_count() << std::endl;

    return 0;
}

strstr

strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL

 int strStr(string haystack, string needle) {
        int result = -1;
        for (int i = 0; i < haystack.size(); i++) {
            int curIndex = i;
            int targetIndex = 0;
            while (haystack[curIndex] == needle[targetIndex] &&
                   curIndex < haystack.size() && targetIndex < needle.size()) {
                curIndex++;
                targetIndex++;
            }
            if (targetIndex == needle.size()) {
                result = i;
                break;
            }
        }
        return result;
    }
#include <iostream>

char* myStrstr(const char* haystack, const char* needle)
{
    // If either string is nullptr, return nullptr
    if (!haystack || !needle)
    {
        return nullptr;
    }

    // If needle is an empty string, return haystack
    if (*needle == '\0')
    {
        return const_cast<char*>(haystack);
    }

    // Iterate over haystack
    for (const char* h = haystack; *h != '\0'; ++h)
    {
        // Pointers for haystack and needle
        const char* h_temp = h;
        const char* n = needle;

        // Compare haystack substring with needle
        while (*h_temp != '\0' && *n != '\0' && *h_temp == *n)
        {
            ++h_temp;
            ++n;
        }

        // If we have reached the end of needle, we have found a match
        if (*n == '\0')
        {
            return const_cast<char*>(h);
        }
    }

    // If no match is found, return nullptr
    return nullptr;
}

int main() {
    const char* haystack = "Hello, world!";
    const char* needle = "world";
    
    char* result = myStrstr(haystack, needle);
    
    if (result)
    {
        std::cout << "Found substring: " << result << std::endl;
    } 
    else
    {
        std::cout << "Substring not found." << std::endl;
    }

    return 0;
}

在最坏情况下,myStrstr 函数的时间复杂度为 O((n-m+1)*m),其中 n 是 haystack 的长度,m 是 needle 的长度

生产者消费者

#include <queue>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
using namespace std;

class MessageQueue
{
public:
	MessageQueue(int maxSize) : m_maxsize(maxSize){};
	~MessageQueue(){
	};

	void put(int value)
	{
		std::unique_lock<std::mutex> lck(m_tex);
		fullCond.wait(lck, [this]{ return m_quque.size() < m_maxsize;});
		m_quque.push(value);
		std::cout << "put: " << value << std::endl;
		lck.unlock(); 
		emptyCond.notify_one();
	}

	int get()
	{
		std::unique_lock<std::mutex> lck(m_tex);
		emptyCond.wait(lck, [this]{ return !m_quque.empty();});
		int value = m_quque.front();
		m_quque.pop(); 
		std::cout << "get: " << value << std::endl;
		lck.unlock(); 
		fullCond.notify_one();
		return value;
	}
	
private:
	int m_maxsize = 0;
	std::condition_variable fullCond, emptyCond;
	std::mutex m_tex;
	std::queue<int> m_quque;
};

void producer(MessageQueue& MessageQu, int id, int count)
{
	std::thread::id this_thread_id = std::this_thread::get_id(); // 获取当前线程的ID
	std::cout << "producer: "<< " " << this_thread_id << std::endl;
	for (int i = 0; i < count; ++i)
	{
		MessageQu.put(id);
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}

void customer(MessageQueue& MessageQu, int id, int count)
{
	std::thread::id this_thread_id = std::this_thread::get_id(); // 获取当前线程的ID
	std::cout << "customer: "<< this_thread_id << std::endl;
	for (int i = 0; i < count; ++i)
	{
		MessageQu.get();
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
}

int main(int argc, char const *argv[])
{
	const int ququeSize = 10;
	const int producerCount = 3;
	const int customerCount = 2;
	const int valueCont = 10;

	MessageQueue MessageQu(ququeSize);

	std::vector<std::thread> producers;
	std::vector<std::thread> customers;

	for (int i = 0; i < producerCount; ++i)
	{
		producers.emplace_back(producer, std::ref(MessageQu), i, valueCont);
	}
	for (int i = 0; i < customerCount; ++i)
	{
		customers.emplace_back(customer, std::ref(MessageQu), i, valueCont);
	}

	for (auto& produ : producers)
	{
		produ.join();
	}
	for(auto& cust : customers)
	{
		cust.join();
	}

	return 0;
}

两个线程交替打印 0 1

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

class Printer
{
public:
    Printer() : turn(0) {}

    void printZero()
    {
        for (int i = 0; i < 10; ++i)
        { // 打印10次,可以根据需要调整
            std::unique_lock<std::mutex> lock(mtx);
            cv.wait(lock, [this]() { return turn == 0; });
            std::cout << "0";
            turn = 1;
            cv.notify_all();
        }
    }

    void printOne()
    {
        for (int i = 0; i < 10; ++i)
        { // 打印10次,可以根据需要调整
            std::unique_lock<std::mutex> lock(mtx);
            cv.wait(lock, [this]() { return turn == 1; });
            std::cout << "1";
            turn = 0;
            cv.notify_all();
        }
    }

private:
    std::mutex mtx;
    std::condition_variable cv;
    int turn; // 用于指示当前该哪个线程打印
};

int main()
{
    Printer printer;

    std::thread t1(&Printer::printZero, &printer);
    std::thread t2(&Printer::printOne, &printer);

    t1.join();
    t2.join();

    return 0;
}