Ethan's Blog


  • Home

  • Archives

  • Tags

  • Search

Scale from Zero to Millions of Users

Posted on 2023-10-13

Designing a system that supports millions of users is challenging, and it is a journey that requires continuous refinement and endless improvement. In this chapter, we build a system that supports a single user and gradually scale it up to serve millions of users. After reading this chapter, you will master a handful of techniques that will help you to crack the system design interview questions.

Single server setup

A journey of a thousand miles begins with a single step, and building a complex system is no different. To start with something simple, everything is running on a single server. Figure 1 shows the illustration of a single server setup where everything is running on one server: web app, database, cache, etc.

Read more »

更加复杂的数据结构

Posted on 2023-04-15

引言

目前为止,我们接触了大量的数据结构,包括利用指针实现的三剑客和 C++ 自带的 STL 等。对于一些题目,我们不仅需要利用多个数据结果解决问题,还需要把这些数据结构进行嵌套和联动,进行更为复杂、更为快速的操作。

并查集

并查集 (Union-Fnd) 可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。假设存在 n 个节点,我们先将所有节点的父亲标为自己;每次要连接节点 i 和 j 时,我们可以将 i 的父亲标为 j;每次要查询两个节点是否相连时,我们可以查找 i 和 j 的祖先是否最终为同一个人:

其中 union 操作可以将两个集合连在一起,find 操作可以查找给定节点的祖先,并且如果可以的话,将集合的层数/高度降低。

684. Redundant Connection
因为需要判断是否两个节点被重复连通,所以我们可以使用并查集来解决此类问题。为了加速查找,我们可以使用路径压缩和按秩合并来优化并查集。

Read more »

指针三剑客之三:图

Posted on 2023-04-13

数据结构介绍

作为指针三剑客之三,图是树的升级版。图通常分为有向 (Directed) 或无向 (Undirected),有循环 (Cyclic) 或无循环 (Acyclic),所有节点相连 (Connected) 或不相连 (Disconnected)。树即是一个相连的无向无环图,而另一种很常见的图是有向无环图 (DAG):

假设图中一共有 n 个节点、m 条边,图通常有两种表示方法:

  • 邻接矩阵 (Adjacency Matrix):我们可以建立一个 n×n 的矩阵 G,如果第 i 个节点连向第 j 个节点,则 G[i][j]=1,反之为 0;如果图是无向的,则这个矩阵一定是对称矩阵,即 G[i][j]=G[j][i];
  • 邻接链表 (Adjacency List):我们可以建立一个大小为 n 的数组,每个位置 i 储存一个数组或者链表,表示第 i 个节点连向的其它节点;

邻接矩阵空间开销比邻接链表大,但是邻接链表不支持快速查找 i 和 j 是否相连,因此两种表示方法可以根据题目需要适当选择。除此之外,我们也可以直接用一个 m×2 的矩阵储存所有的边。

Read more »

指针三剑客之二:树

Posted on 2023-04-10

数据结构介绍

作为单链表的升级版,我们通常接触的树都是二叉树 (Binary Tree),即每个节点最多有两个子节点;且除非题目说明,默认树中不存在循环结构。LeetCode 默认的树表示方法如下:

1
2
3
4
5
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right

可以看出,其与链表的主要差别就是多了一个子节点的指针。

Read more »

指针三剑客之一:链表

Posted on 2023-04-07

数据结构介绍

单向链表是由节点和指针构成的数据结构,每个节点存有一个值,和一个指向下一个节点的指针,因此很多链表问题可以用递归来处理。不同于数组,链表并不能直接获取任意节点的值,必须要通过指针找到该节点后才能获取其值。同理,在未遍历到链表结尾时,我们也无法知道链表的长度,除非依赖其他数据结构储存长度。LeetCode 默认的链表表示方法如下:

1
2
3
4
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next

由于在进行链表操作时,尤其是删除节点时,经常会因为对当前节点进行操作而导致内存或指针出现问题。有两个小技巧可以解决这个问题:

  • 尽量处理当前节点的下一个节点而非当前节点本身。
  • 建立一个虚拟节点 (Dummy Node),使其指向当前链表的头节点,这样即使原链表所有节点全被删除,也会有一个 dummy 存在,返回 dummy->next 即可。

一般来说,算法题不需要删除内存。在刷 LeetCode 的时候,如果想要删除一个节点,可以直接进行指针操作而无需回收内存。实际做软件工程时,对于无用的内存,笔者建议尽量显式回收,或利用智能指针。

Read more »
1…456…55
necusjz

necusjz

274 posts
16 tags
© 2016 - 2025 necusjz
Powered by Hexo
Theme - NexT.Mist