C++冲鸭~【数据结构】

前言

此篇博客是学习笔记,根据Hello算法学习。GitHub链接:https://github.com/krahets/hello-algo

数组arr

初始化

int arr[5];
// 存储在栈上
int nums[5] { 1, 23, 45 }
// 存储在堆上
int* arr1 = new int[5];
int* num1 = new int[5] {1, 2, 3, 4, 5}

访问元素

// 随机访问元素
int randomAccess(int *nums, int size){
	int randomIndex = rand() % size;
	int randomNum = nums[randomIndex];
	return randomNum;
}

插入元素

void insert(int *nums, int size, int num, int index) {
	for (int i=size-1; i > index; i--) {
		nums[i] = nums[i-1];
	}
	nums[index] = num;
}

删除元素

void remove(int *nums, int size, int index){
	for(int i=index; i < size-1; i++){
		nums[i] = nums[i+1];
	}
}

查找元素

int find(int *num, int size, int target){
	for (int i=0; i<size; i++) {
		if(nums[i] == target)
			return i;
	}
	return -1;
}

扩容数组

int *extend(int *nums, int size, int enlarge) {
	// 初始化一个扩展长度后的数组
	int *res = new int[size + enlarge];
	for (int i=0; i<size; i++) {
		res[i]  = nums[i];
	}
	delete[] nums;  // 释放内存
	return res;
}

链表

struct ListNode {
	int val;			// 节点值
	ListNode *next;		// 指向下一节点
	ListNode(int x) : val(x), next(nullptr) {}  // 构造函数
};

初始化

/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
// 初始化各个节点
ListNode* n0 = new ListNode(1);
ListNode* n1 = new ListNode(3);
ListNode* n2 = new ListNode(2);
ListNode* n3 = new ListNode(5);
ListNode* n4 = new ListNode(4);
// 构建引用指向
n0->next = n1;
n1->next = n2;
n2->next = n3;
n3->next = n4;

插入节点

void insert(ListNode *n0, ListNode *p) {
	ListNode *n1 = n0->next;
	P->next = n1;
	n0->next = P;
}

删除节点

void remove(ListNode *n0) {
	if (n0->next == nullptr)
		return;
	// n0 -> P -> n1
	ListNode *P = n0 -> next;
	ListNode *n1 = P->next;
	n0->next = n1;
	delete P;	// 释放内存
}

访问节点

ListNode *access(ListNode *head, int index) {
	for (int i=0; i<index; i++) {
		if (head == nullptr)
			return nullptr;
			head = head->next; 
	}
	return head;
}

查找节点

int find(ListNode *head, int target) {
	int index = 0;
	while (head != nullptr) {
		if (head->val == target)
			return index;
		head = head->next;
		index++;
	}
	return -1;
}

常见链表类型

  • 单向链表
  • 环形链表
  • 双向链表
struct ListNode {
	int val;
	ListNode *next;
	ListNode *prev;
	ListNode(int x) : val(x), next(nullptr), prev(nullptr) {}	// 构造函数
};

列表

初始化

/*初始化列表*/
vector<int> list1;
vector<int> list = { 1, 3, 2, 5, 4 };

访问元素

list num = list[1];
list[1] = 0;

插入与删除元素

相较于数组,列表可以自由地添加与删除元素。在列表尾部添加元素的时间复杂度O(1),但插入和删除元素的效率仍与数组相同,为O(n)。

list.clear(); 	// 清空列表

list.push_back(1);
list.push_back(3);
list.push_back(2);
list.push_back(5);
list.push_back(4);

list.insert(list.begin() + 3, 6);	// 在索引 3 处插入数字 6
list.erase(list.begin() + 3);		// 删除索引 3 处的元素

遍历列表

// 通过索引遍历
int count = 0;
for (int i=0; i<list.size(); i++) {
	count++;
}

// 直接遍历
count = 0;
for (int n : list) {
	count++;
}

拼接列表

vector<int> list1 = { 6, 8, 7, 10, 9 };
// 将list1 拼接到list之后
list.insert(list.end(), list1.begin(), list1.end());

排序列表

sort(list.begin(), list.end());		// 排序后,列表元素由小到大排列

列表实现

class MyList {
	private:
		int *nums;					// 数组(存储列表元素)
		int numsCapacity = 10;		// 列表容量
		int numsSize = 0;			// 列表长度(当前元素数量)
		int extendRatio = 2;		// 每次列表扩容的倍数

	public:
		// 构造方法
		MyList() {
			nums = new int[numsCapacity];
		}
		// 析构方法
		~MyList() {
			delete[] nums;
		}
		// 获取列表长度
		int size() {
			return numsSize;
		}
		// 获取列表容量
		int capacity() {
			return numsCapacity;
		}
};

// 初始化栈
stack<int> stack;

stack.push(1);
stack.push(3);
stack.push(2);
stack.push(5);
stack.push(4);

int top = stack.top();	// 访问栈顶元素
stack.pop();			// 出栈(无返回值)
int size = stack.size();	// 栈的长度
bool empty = stack.empty();		// 判断是否为空

基于链表的实现栈

class LinkedListStack {
	private:
		ListNode *stackTop;
		int stkSize;

	public:
		LinkedListStack(){
			stackTop = nullptr;
			stkSize = 0;
		}

		~LinkedListStack() {
			freeMemoryLinkedList(stackTop);
		}
	
		int size(){
			return stkSize;
		}

		bool isEmpty() {
			return size() == 0;
		}

		void push(int num) {
			ListNode *node = new ListNode(num);
			node->next = stackTop;
			stackTop = node;
			stkSize++;
		}

		void pop(){
			int num = top();
			ListNode *tmp = stackTop;
			stackTop = stackTop->next;
			delete tmp;
			stkSize--;
		}

		int top() {
			if (isEmpty())
				throw out_of_range("栈为空")return stackTop->val;
		}

		vector<int> toVector() {
			ListNode *node = stackTop;
			vector<int> res(size());
			for (int i=res.size() - 1; i>=0; i--) {
				res[i] = node->val;
				node = node->next;
			}
			return res;
		}
};

基于数组的实现

class ArrayStack {
	private:
		vector<int> stack;

	public:
		int size(){
			return stack.size();
		}

		bool isEmpty() {
			return stack.size() == 0;
		}

		void push(int num) {
			stack.push_back(num);
		}

		void pop(){
			int oldTop = top();
			stack.pop_back():
		}

		int top() {
			if(isEmpty())
				throw out_of_range("栈为空");
			return stack.back();
		}
		vector<int> toVector(){
			return stack;
		}
};

队列

queue<int> queue;	// 初始化队列

queue.push(1);
queue.push(3);
queue.push(2);
queue.push(5);
queue.push(4);

int front = queue.front();
queue.pop():
int size = queue.size();
bool empty = queue.empty();

基于链表实现队列

/* 基于链表实现的队列 */
class LinkedListQueue {
  private:
    ListNode *front, *rear; // 头节点 front ,尾节点 rear
    int queSize;

  public:
    LinkedListQueue() {
        front = nullptr;
        rear = nullptr;
        queSize = 0;
    }

    ~LinkedListQueue() {
        // 遍历链表删除节点,释放内存
        freeMemoryLinkedList(front);
    }

    /* 获取队列的长度 */
    int size() {
        return queSize;
    }

    /* 判断队列是否为空 */
    bool isEmpty() {
        return queSize == 0;
    }

    /* 入队 */
    void push(int num) {
        // 尾节点后添加 num
        ListNode *node = new ListNode(num);
        // 如果队列为空,则令头、尾节点都指向该节点
        if (front == nullptr) {
            front = node;
            rear = node;
        }
        // 如果队列不为空,则将该节点添加到尾节点后
        else {
            rear->next = node;
            rear = node;
        }
        queSize++;
    }

    /* 出队 */
    void pop() {
        int num = peek();
        // 删除头节点
        ListNode *tmp = front;
        front = front->next;
        // 释放内存
        delete tmp;
        queSize--;
    }

    /* 访问队首元素 */
    int peek() {
        if (size() == 0)
            throw out_of_range("队列为空");
        return front->val;
    }

    /* 将链表转化为 Vector 并返回 */
    vector<int> toVector() {
        ListNode *node = front;
        vector<int> res(size());
        for (int i = 0; i < res.size(); i++) {
            res[i] = node->val;
            node = node->next;
        }
        return res;
    }
};

基于数组的实现队列

/* 基于环形数组实现的队列 */
class ArrayQueue {
  private:
    int *nums;       // 用于存储队列元素的数组
    int front;       // 队首指针,指向队首元素
    int queSize;     // 队列长度
    int queCapacity; // 队列容量

  public:
    ArrayQueue(int capacity) {
        // 初始化数组
        nums = new int[capacity];
        queCapacity = capacity;
        front = queSize = 0;
    }

    ~ArrayQueue() {
        delete[] nums;
    }

    /* 获取队列的容量 */
    int capacity() {
        return queCapacity;
    }

    /* 获取队列的长度 */
    int size() {
        return queSize;
    }

    /* 判断队列是否为空 */
    bool isEmpty() {
        return size() == 0;
    }

    /* 入队 */
    void push(int num) {
        if (queSize == queCapacity) {
            cout << "队列已满" << endl;
            return;
        }
        // 计算队尾指针,指向队尾索引 + 1
        // 通过取余操作,实现 rear 越过数组尾部后回到头部
        int rear = (front + queSize) % queCapacity;
        // 将 num 添加至队尾
        nums[rear] = num;
        queSize++;
    }

    /* 出队 */
    void pop() {
        int num = peek();
        // 队首指针向后移动一位,若越过尾部则返回到数组头部
        front = (front + 1) % queCapacity;
        queSize--;
    }

    /* 访问队首元素 */
    int peek() {
        if (isEmpty())
            throw out_of_range("队列为空");
        return nums[front];
    }

    /* 将数组转化为 Vector 并返回 */
    vector<int> toVector() {
        // 仅转换有效长度范围内的列表元素
        vector<int> arr(queSize);
        for (int i = 0, j = front; i < queSize; i++, j++) {
            arr[i] = nums[j % queCapacity];
        }
        return arr;
    }
};

双向队列

deque<int> deque;

deque.push_back(2);		// 添加到队尾
deque.push_back(5);
deque.push_back(4);
deque.push_front(3);	// 添加到队首
deque.push_front(1);

int front = deque.front();
int back = deque.back();

int size = deque.size();
bool empty = deque.empty();

哈希表

unordered_map<int, string> map;		// 初始化

// 添加操作
map[5] = "哈";
map[8] = "希";
map[46] = "表";

string name = map[8];	// 输入键key,得到值value

map.erase(8);	// 删除哈希表中的键值对

哈希表的三种遍历方式

/* 遍历哈希表 */
// 遍历键值对 key->value
for (auto kv: map) {
    cout << kv.first << " -> " << kv.second << endl;
}
// 单独遍历键 key
for (auto key: map) {
    cout << key.first << endl;
}
// 单独遍历值 value
for (auto val: map) {
    cout << val.second << endl;
}

哈希表的简单实现

/* 键值对 */
struct Pair {
  public:
    int key;
    string val;
    Pair(int key, string val) {
        this->key = key;
        this->val = val;
    }
};

/* 基于数组简易实现的哈希表 */
class ArrayHashMap {
  private:
    vector<Pair *> buckets;

  public:
    ArrayHashMap() {
        // 初始化数组,包含 100 个桶
        buckets = vector<Pair *>(100);
    }

    ~ArrayHashMap() {
        // 释放内存
        for (const auto &bucket : buckets) {
            delete bucket;
        }
        buckets.clear();
    }

    /* 哈希函数 */
    int hashFunc(int key) {
        int index = key % 100;
        return index;
    }

    /* 查询操作 */
    string get(int key) {
        int index = hashFunc(key);
        Pair *pair = buckets[index];
        if (pair == nullptr)
            return nullptr;
        return pair->val;
    }

    /* 添加操作 */
    void put(int key, string val) {
        Pair *pair = new Pair(key, val);
        int index = hashFunc(key);
        buckets[index] = pair;
    }

    /* 删除操作 */
    void remove(int key) {
        int index = hashFunc(key);
        // 释放内存并置为 nullptr
        delete buckets[index];
        buckets[index] = nullptr;
    }

    /* 获取所有键值对 */
    vector<Pair *> pairSet() {
        vector<Pair *> pairSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                pairSet.push_back(pair);
            }
        }
        return pairSet;
    }

    /* 获取所有键 */
    vector<int> keySet() {
        vector<int> keySet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                keySet.push_back(pair->key);
            }
        }
        return keySet;
    }

    /* 获取所有值 */
    vector<string> valueSet() {
        vector<string> valueSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                valueSet.push_back(pair->val);
            }
        }
        return valueSet;
    }

    /* 打印哈希表 */
    void print() {
        for (Pair *kv : pairSet()) {
            cout << kv->key << " -> " << kv->val << endl;
        }
    }
};

二叉树

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

初始化二叉树

TreeNode* n1 = new TreeNode(1);
TreeNode* n2 = new TreeNode(2);
TreeNode* n3 = new TreeNode(3);
TreeNode* n4 = new TreeNode(4);
TreeNode* n5 = new TreeNode(5);

n1->left = n2;
n1->right = n3;
n2->left = n4;
n2->right = n5;

插入和删除节点

TreeNode* P = new TreeNode(0);
// 在n1->n2中间插入P节点
n1->left = P;
P->left = n2;
// 删除P节点
n1->left = n2;

二叉树的遍历

层序遍历

使用队列来实现,队列“先进先出”,层序遍历“逐层推进”。

vector<int> levelOrder(TreeNode *root){
	queue<TreeNode *> queue;
	queue.push(root);
	vector<int> vec;
	while(!queue.empty()){
		TreeNode *node = queue.front();
		queue.pop();
		vec.push_back(node_val);
		if(node->left != nullptr)
			queue.push(node->left);
		if(node->right != nullptr)
			queue.push(node->right);
	}
	return vec;
}

前序/中序/后序

void preOrder(TreeNode *root) {
	if (root != nullptr)
		return ;
	// 根左右
	vec.push_back(root->val);
	preOrder(root->left);
	preOrder(root->right);
}

void inOrder(TreeNode *root) {
	if (root != nullptr)
		return ;
	// 左根右
	inOrder(root->left);
	vec.push_back(root->val);
	inOrder(root->right);
}

void postOrder(TreeNode *root) {
	if (root != nullptr)
		return ;
	// 左右根
	postOrder(root->left);
	postOrder(root->right);
	vec.push_back(root->val);
}

二叉树数组表示

/* 二叉树的数组表示 */
// 使用int 最大值 INT_MAX 标记空位
vector<int> tree = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
class ArrayBinaryTree {
	public:
		ArrayBinaryTree(vector<int> arr) {
			tree = arr;
		}

		int size(){
			return tree.size();
		}

		int val(int i){
			if(i < 0 || i >= size())
				return INT_MAX;
			return tree[i];
		}
	
		int left(int i) {
			return 2 * i + 1;
		}
		int right(int i) {
			return 2 * i + 2;
		}

		int parent(int i) {
			return (i - 1) / 2;
		}

		vector<int> levelOrder() {
			vector<int> res;
			for(int i=0; i<size(); i++) {
				if (val(i) != INT_MAX)
					res.push_back(val(i));
			}
			return res;
		}
		// 前序
		vector<int> preOrder() {
			vector<int> res;
			dfs(0, "pre", res);
			return res;
		}
		// 中序
		vector<int> inOrder(){
			vector<int> res;
			dfs(0, "in", res);
			return res;
		}
		// 后序
		vector<int> postOrder(){
			vector<int> res;
			dfs(0, "post", res);
			return res;
		}

	private:
		vector<int> tree;
		void dfs(int i, string order, vector<int> &res) {
        // 若为空位,则返回
        if (val(i) == INT_MAX)
            return;
        // 前序遍历
        if (order == "pre")
            res.push_back(val(i));
        dfs(left(i), order, res);
        // 中序遍历
        if (order == "in")
            res.push_back(val(i));
        dfs(right(i), order, res);
        // 后序遍历
        if (order == "post")
            res.push_back(val(i));
    }
};

二叉搜索树

【左子树的所有节点的值<根节点的值<右子树的所有节点的值】

查找节点

TreeNode *search(int num) {
	TreeNode *cur = root;

	while (cur != nullptr) {
		if(cur->val < num) 
			cur = cur->right;
		else if (cur->val > num)
			cur = cur->left;
		else
			break;
	}
	return cur;
}

插入节点

void insert(int num) {
	if (root == nullptr){
		root = new TreeNode(num);
		return;
	}
	TreeNode *cur = root, *pre = nullptr;
	while (cur != nullptr) {
        // 找到重复节点,直接返回
        if (cur->val == num)
            return;
        pre = cur;
        // 插入位置在 cur 的右子树中
        if (cur->val < num)
            cur = cur->right;
        // 插入位置在 cur 的左子树中
        else
            cur = cur->left;
    }
    // 插入节点
    TreeNode *node = new TreeNode(num);
    if (pre->val < num)
        pre->right = node;
    else
        pre->left = node;
}

删除节点

/* 删除节点 */
void remove(int num) {
    // 若树为空,直接提前返回
    if (root == nullptr)
        return;
    TreeNode *cur = root, *pre = nullptr;
    // 循环查找,越过叶节点后跳出
    while (cur != nullptr) {
        // 找到待删除节点,跳出循环
        if (cur->val == num)
            break;
        pre = cur;
        // 待删除节点在 cur 的右子树中
        if (cur->val < num)
            cur = cur->right;
        // 待删除节点在 cur 的左子树中
        else
            cur = cur->left;
    }
    // 若无待删除节点,则直接返回
    if (cur == nullptr)
        return;
    // 子节点数量 = 0 or 1
    if (cur->left == nullptr || cur->right == nullptr) {
        // 当子节点数量 = 0 / 1 时, child = nullptr / 该子节点
        TreeNode *child = cur->left != nullptr ? cur->left : cur->right;
        // 删除节点 cur
        if (cur != root) {
            if (pre->left == cur)
                pre->left = child;
            else
                pre->right = child;
        } else {
            // 若删除节点为根节点,则重新指定根节点
            root = child;
        }
        // 释放内存
        delete cur;
    }
    // 子节点数量 = 2
    else {
        // 获取中序遍历中 cur 的下一个节点
        TreeNode *tmp = cur->right;
        while (tmp->left != nullptr) {
            tmp = tmp->left;
        }
        int tmpVal = tmp->val;
        // 递归删除节点 tmp
        remove(tmp->val);
        // 用 tmp 覆盖 cur
        cur->val = tmpVal;
    }
}

堆是一种满足特定条件的完全二叉树,主要可分为小顶堆和大顶堆。

堆常用操作

//初始化堆
// 初始化小顶堆
priority_queue<int, vector<int>, greater<int>> minHeap;
// 初始化大顶堆
priority_queue<int, vector<int>, less<int>> maxHeap;

// 元素入堆
maxHeap.push(1);
maxHeap.push(3);
maxHeap.push(2);
maxHeap.push(5);
maxHeap.push(4);

//获取堆顶元素
int peek = maxHeap.top();

// 堆顶元素出堆【出堆元素会形成一个从大到小的序列】
 maxHeap.pop(); // 5
 maxHeap.pop(); // 4
 maxHeap.pop(); // 3
 maxHeap.pop(); // 2
 maxHeap.pop(); // 1

// 获取堆的大小
int size = maxHeap.size();

// 判断堆是否为空
bool isEmpty = maxHeap.empty();

// 输入列表并建堆
vector<int> input{1, 3, 2, 5, 4};
priority_queue<int, vector<int>, greater<int>> minHeap(input.begin(), input.end());

堆的实现

堆的存储和表示

// 获取左子节点索引
int left(int i) {
	return 2 * i + 1;
}

// 获取右子节点索引
int right(int i) {
	return 2 * i + 2;
}

// 获取父节点索引
int parent(int i) {
	return (i - 1) / 2; // 向下取整
}

访问堆顶元素

int peek() {
	return maxHeap[0];
}

元素入堆

void push(int val) {
	// 添加节点
	maxHeap.push_back(val);
	siftUp(size() - 1);
}

void siftUp( int i ) {
	while (true) {
		int p = parent(i);
		if (p < 0 || maxHeap[i] <= maxHeap[p])
			break;
		swap(maxHeap[i], maxHeap[p]);
		i = p;
	}
}

堆顶元素出堆

// 元素出堆
void pop(){
	if ( isEmpty() ) {
		throw out_of_range("堆位空");
	}
	swap(maxHeap[0], maxHeap[size() - 1]);
	// 删除节点
	maxHeap.pop_back();
	siftDown(0);
}
void siftDown(int i) {
	while(true) {
		int l = left(i), r = right(i), ma = i;
		if (l<size() && maxHeap[l] > maxHeap[ma])
			ma = l;
		if (r<size() && maxHeap[r] > maxHeap[ma])
			ma = r;
		if (ma == i)
			break;
		swap(maxHeap[i], maxHeap[ma]);
		i = ma;
	}
}

建堆操作

MaxHeap(vector<int> nums) {
	maxHeap = nums;
	for ( int i = parent(size() - 1); i >= 0; i--) {
		siftDown(i);
	}
}

图基础操作

基于邻接矩阵的实现

// 基于邻接矩阵实现的无向图类
/* 基于邻接矩阵实现的无向图类 */
class GraphAdjMat {
    vector<int> vertices;       // 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
    vector<vector<int>> adjMat; // 邻接矩阵,行列索引对应“顶点索引”

  public:
    /* 构造方法 */
    GraphAdjMat(const vector<int> &vertices, const vector<vector<int>> &edges) {
        // 添加顶点
        for (int val : vertices) {
            addVertex(val);
        }
        // 添加边
        // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引
        for (const vector<int> &edge : edges) {
            addEdge(edge[0], edge[1]);
        }
    }

    /* 获取顶点数量 */
    int size() const {
        return vertices.size();
    }

    /* 添加顶点 */
    void addVertex(int val) {
        int n = size();
        // 向顶点列表中添加新顶点的值
        vertices.push_back(val);
        // 在邻接矩阵中添加一行
        adjMat.emplace_back(vector<int>(n, 0));
        // 在邻接矩阵中添加一列
        for (vector<int> &row : adjMat) {
            row.push_back(0);
        }
    }

    /* 删除顶点 */
    void removeVertex(int index) {
        if (index >= size()) {
            throw out_of_range("顶点不存在");
        }
        // 在顶点列表中移除索引 index 的顶点
        vertices.erase(vertices.begin() + index);
        // 在邻接矩阵中删除索引 index 的行
        adjMat.erase(adjMat.begin() + index);
        // 在邻接矩阵中删除索引 index 的列
        for (vector<int> &row : adjMat) {
            row.erase(row.begin() + index);
        }
    }

    /* 添加边 */
    // 参数 i, j 对应 vertices 元素索引
    void addEdge(int i, int j) {
        // 索引越界与相等处理
        if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
            throw out_of_range("顶点不存在");
        }
        // 在无向图中,邻接矩阵沿主对角线对称,即满足 (i, j) == (j, i)
        adjMat[i][j] = 1;
        adjMat[j][i] = 1;
    }

    /* 删除边 */
    // 参数 i, j 对应 vertices 元素索引
    void removeEdge(int i, int j) {
        // 索引越界与相等处理
        if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
            throw out_of_range("顶点不存在");
        }
        adjMat[i][j] = 0;
        adjMat[j][i] = 0;
    }

    /* 打印邻接矩阵 */
    void print() {
        cout << "顶点列表 = ";
        printVector(vertices);
        cout << "邻接矩阵 =" << endl;
        printVectorMatrix(adjMat);
    }
};

基于领接表的实现

/* 基于邻接表实现的无向图类 */
class GraphAdjList {
  public:
    // 邻接表,key: 顶点,value:该顶点的所有邻接顶点
    unordered_map<Vertex *, vector<Vertex *>> adjList;

    /* 在 vector 中删除指定节点 */
    void remove(vector<Vertex *> &vec, Vertex *vet) {
        for (int i = 0; i < vec.size(); i++) {
            if (vec[i] == vet) {
                vec.erase(vec.begin() + i);
                break;
            }
        }
    }

    /* 构造方法 */
    GraphAdjList(const vector<vector<Vertex *>> &edges) {
        // 添加所有顶点和边
        for (const vector<Vertex *> &edge : edges) {
            addVertex(edge[0]);
            addVertex(edge[1]);
            addEdge(edge[0], edge[1]);
        }
    }

    /* 获取顶点数量 */
    int size() {
        return adjList.size();
    }

    /* 添加边 */
    void addEdge(Vertex *vet1, Vertex *vet2) {
        if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
            throw invalid_argument("不存在顶点");
        // 添加边 vet1 - vet2
        adjList[vet1].push_back(vet2);
        adjList[vet2].push_back(vet1);
    }

    /* 删除边 */
    void removeEdge(Vertex *vet1, Vertex *vet2) {
        if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
            throw invalid_argument("不存在顶点");
        // 删除边 vet1 - vet2
        remove(adjList[vet1], vet2);
        remove(adjList[vet2], vet1);
    }

    /* 添加顶点 */
    void addVertex(Vertex *vet) {
        if (adjList.count(vet))
            return;
        // 在邻接表中添加一个新链表
        adjList[vet] = vector<Vertex *>();
    }

    /* 删除顶点 */
    void removeVertex(Vertex *vet) {
        if (!adjList.count(vet))
            throw invalid_argument("不存在顶点");
        // 在邻接表中删除顶点 vet 对应的链表
        adjList.erase(vet);
        // 遍历其他顶点的链表,删除所有包含 vet 的边
        for (auto &adj : adjList) {
            remove(adj.second, vet);
        }
    }

    /* 打印邻接表 */
    void print() {
        cout << "邻接表 =" << endl;
        for (auto &adj : adjList) {
            const auto &key = adj.first;
            const auto &vec = adj.second;
            cout << key->val << ": ";
            printVector(vetsToVals(vec));
        }
    }
};

图的遍历

广度优先搜索

/* 广度优先遍历 BFS */
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) {
    // 顶点遍历序列
    vector<Vertex *> res;
    // 哈希表,用于记录已被访问过的顶点
    unordered_set<Vertex *> visited = {startVet};
    // 队列用于实现 BFS
    queue<Vertex *> que;
    que.push(startVet);
    // 以顶点 vet 为起点,循环直至访问完所有顶点
    while (!que.empty()) {
        Vertex *vet = que.front();
        que.pop();          // 队首顶点出队
        res.push_back(vet); // 记录访问顶点
        // 遍历该顶点的所有邻接顶点
        for (auto adjVet : graph.adjList[vet]) {
            if (visited.count(adjVet))
                continue;            // 跳过已被访问过的顶点
            que.push(adjVet);        // 只入队未访问的顶点
            visited.emplace(adjVet); // 标记该顶点已被访问
        }
    }
    // 返回顶点遍历序列
    return res;
}

深度优先搜索

/* 深度优先遍历 DFS 辅助函数 */
void dfs(GraphAdjList &graph, unordered_set<Vertex *> &visited, vector<Vertex *> &res, Vertex *vet) {
    res.push_back(vet);   // 记录访问顶点
    visited.emplace(vet); // 标记该顶点已被访问
    // 遍历该顶点的所有邻接顶点
    for (Vertex *adjVet : graph.adjList[vet]) {
        if (visited.count(adjVet))
            continue; // 跳过已被访问过的顶点
        // 递归访问邻接顶点
        dfs(graph, visited, res, adjVet);
    }
}

/* 深度优先遍历 DFS */
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
vector<Vertex *> graphDFS(GraphAdjList &graph, Vertex *startVet) {
    // 顶点遍历序列
    vector<Vertex *> res;
    // 哈希表,用于记录已被访问过的顶点
    unordered_set<Vertex *> visited;
    dfs(graph, visited, res, startVet);
    return res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值