一开始说了,数据结构可以直接概括成两部分:数组和链表,我就从这个思路 真对数组,链表,然后再结合递归来实现树,还有队列,栈可以使用STL模版中相关的库函数来实现,当然还有hashmap。
数组vector的⼏种常⻅操作 :
创建和构造 :
静态数组初始化:
int array[N][N] = {{1,2,34,5},{7,8,40,10},{2323,12,24}}
vector的几种操作方法:
std::vector<int> vec(10, 0); // 创建⼀个⼤⼩为10,所有元素初始化为0的vector
//从⼀个vector 拷⻉到另⼀个vector : 拷⻉构造函数
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2(vec1);
//元素访问的两种⽅式:
int value = vec.at(0);
int value = vec[0];
//front 和 back:访问第⼀个和最后⼀个元素。
int first = vec.front();
int last = vec.back();
//修改元素
vec[0] = 10;
//尾部插⼊⼀个元素:
vec.push_back(10);
vec.pop_back();
//移除指定位置的元素
vec.erase(vec.begin() + 1); // 移除索引1的元素
//遍历数组
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
//swap()交换数据
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5, 6};
vec1.swap(vec2);
链表头结点的定义:
struct ListNode {
int val; // 数据域
ListNode* next; // 指针域,指向下⼀个节点
ListNode(int x) : val(x), next(nullptr) {} // 构造函数
};
头插法创建链表
// 使⽤头插法创建链表
ListNode* createLinkedList(const vector<int>& values) {
ListNode* head = nullptr; // 初始化头节点为nullptr
for (int value : values) {
ListNode* newNode = new ListNode(value); // 创建新节点
newNode->next = head; // 新节点的next指向当前头节点
head = newNode; // 更新头节点为新节点
}
return head; // 返回头节点
}
用尾差法来创建链表
// 使⽤尾插法创建链表
ListNode* createLinkedList(const vector<int>& values) {
ListNode* head = nullptr; // 初始化头节点为nullptr
ListNode* tail = nullptr; // 初始化尾节点为nullptr
for (int value : values) {
ListNode* newNode = new ListNode(value); // 创建新节点
if (tail == nullptr) {
head = newNode; // 如果链表为空,新节点成为头节点
} else {
tail->next = newNode; // 否则,将新节点连接到尾节点的后⾯
}
tail = newNode; // 更新尾节点为新节点
}
return head; // 返回头节点
}
要记得成对的思维,创建和内存回收要成对出现。
// 释放链表内存
void freeLinkedList(ListNode* head) {
while (head != nullptr) {
ListNode* temp = head;
head = head->next;
delete temp;
}
}
访问链表的中点:
如何访问链表的中点:使⽤快慢指针法来找到链表的中点。快指针每次移动两步,慢指针每次移动
⼀步。当快指针到达链表末尾时,慢指针将指向链表的中点
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow = head; // 慢指针
ListNode* fast = head; // 快指针
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // 慢指针每次移动⼀步
fast = fast->next->next; // 快指针每次移动两步
}
return slow; // 当快指针到达末尾时,慢指针指向中点
}
};
创建一棵树
定义一个TreeNOde:
class TreeNode {
public:
int val;
vector<TreeNode*> children;
TreeNode(int x) : val(x) {}
};
构建树结构:
TreeNode* buildTree(vector<int>& values) {
if (values.empty()) return nullptr;
queue<TreeNode*> q;
TreeNode* root = new TreeNode(values[0]);
q.push(root);
int i = 1;
while (!q.empty() && i < values.size()) {
TreeNode* node = q.front();
q.pop();
if (i < values.size() && values[i] != -1) {
node->children.push_back(new TreeNode(values[i]));
q.push(node->children.back());
}
i++;
}
return root;
}
树的遍历
DFS:前序遍历: 根——左——右
void preorderTraversal(TreeNode* root) {
if (!root) return;
cout << root->val << " "; // 访问根节点
preorderTraversal(root->left); // 遍历左子树
preorderTraversal(root->right); // 遍历右子树
}
非递归实现,使用栈来实现递归的功能
void preorderTraversal(TreeNode* root) {
if (!root) return;
stack<TreeNode*> st;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
cout << node->val << " "; // 访问根节点
if (node->right) st.push(node->right); // 右子树先入栈
if (node->left) st.push(node->left); // 左子树后入栈
}
}
广度优先遍历,BFS的实现
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
void bfs(vector<vector<int>>& adj, int start) {
int n = adj.size();
vector<bool> visited(n, false);
queue<int> q;
q.push(start);
visited[start] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
cout << u << " ";
for (int v : adj[u]) {
if (!visited[v]) {
visited[v] = true;
q.push(v);
}
}
}
}
int main() {
vector<vector<int>> adj = {
{1, 2}, {0, 2, 3}, {0, 1, 4}, {1, 4}, {2, 3}
};
bfs(adj, 0);
return 0;
}
visited 数组的重要性
防止无限循环:在图中可能存在环,如果没有 visited 数组,算法可能会陷入无限循环。
提高效率:避免重复访问同一个节点,减少不必要的计算。
希望这些信息能帮助你更好地理解 visited 数组在广度优先遍历中的作用。