您现在的位置是:首页 >学无止境 >数据结构和算法网站首页学无止境

数据结构和算法

勒布朗-前端 2024-10-14 00:01:03
简介数据结构和算法

实现一个LRU缓存

LRU缓存是一种常见的缓存算法,它的全称是Least Recently Used,即最近最少使用。LRU缓存的基本思想是,当缓存空间不足时,将最近最少使用的缓存数据删除,以腾出空间存储新的数据。

以下是一个简单的JavaScript实现LRU缓存的示例代码:

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }


  get(key) {
    if (this.cache.has(key)) {
      const value = this.cache.get(key);
      this.cache.delete(key);
      this.cache.set(key, value);
      return value;
    } else {
      return -1;
    }
  }

  put(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}

在这个实现中,LRUCache类有两个方法:get和put。

get方法用于获取缓存中指定key的值,如果缓存中不存在该key,则返回-1。如果缓存中存在该key,则将其从缓存中删除,并重新插入到缓存中,以更新其最近使用的时间。

put方法用于向缓存中插入新的key-value对,如果缓存中已经存在该key,则将其从缓存中删除。如果缓存已满,则删除最近最少使用的key-value对,以腾出空间存储新的数据。

LRUCache类使用Map来实现缓存,Map是一种键值对的集合,可以快速查找指定key的值。LRUCache类的capacity属性表示缓存的最大容量,当缓存中的key-value对数量超过capacity时,LRUCache类会自动删除最近最少使用的key-value对。

求环状链表

环状链表是一种特殊的链表,它的最后一个节点指向链表中的某个节点,形成一个环。在JavaScript中,可以使用对象来表示链表节点,每个节点包含一个值和一个指向下一个节点的指针。为了实现环状链表,需要将最后一个节点的指针指向链表中的某个节点。以下是一个简单的JavaScript实现环状链表的示例代码:

class ListNode {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}

function createCircularLinkedList(arr, pos) {
  const head = new ListNode(arr[0]);
  let curr = head;
  let tail = null;
  for (let i = 1; i < arr.length; i++) {
    const node = new ListNode(arr[i]);
    curr.next = node;
    curr = node;
    if (i === pos) {
      tail = node;
    }
  }
  curr.next = tail;
  return head;
}

在这个实现中,ListNode类表示链表节点,包含一个值val和一个指向下一个节点的指针next。createCircularLinkedList函数用于创建环状链表,接受一个数组arr和一个整数pos作为参数,其中arr表示链表中每个节点的值,pos表示环的起始位置(即最后一个节点指向的节点的位置)。函数首先创建链表的头节点head,并将其指向数组中的第一个元素。然后,函数遍历数组中的每个元素,创建一个新的节点,并将其添加到链表的末尾。如果当前节点的位置等于pos,则将其设置为链表的尾节点tail。最后,将链表的尾节点的指针指向pos位置的节点,形成一个环状链表,并返回链表的头节点head。

使用这个实现,可以创建一个环状链表,并对其进行遍历、插入、删除等操作。例如,可以使用以下代码创建一个包含5个节点的环状链表,并输出链表中每个节点的值:

const arr = [1, 2, 3, 4, 5];
const pos = 2;
const head = createCircularLinkedList(arr, pos);
let curr = head;
for (let i = 0; i < arr.length; i++) {
  console.log(curr.val);
  curr = curr.next;
}

 树的前序、中序、后序遍历

 树的遍历是指按照一定的顺序访问树中的所有节点。常见的树的遍历方式有前序遍历、中序遍历和后序遍历。

前序遍历是指先访问根节点,然后按照从左到右的顺序依次访问左子树和右子树。

中序遍历是指先访问左子树,然后访问根节点,最后访问右子树。

后序遍历是指先访问左子树,然后访问右子树,最后访问根节点。

以下是一个简单的JavaScript实现树的前序、中序、后序遍历的示例代码:

class TreeNode {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}

function preorderTraversal(root) {
  const res = [];
  function traverse(node) {
    if (!node) return;
    res.push(node.val);
    traverse(node.left);
    traverse(node.right);
  }
  traverse(root);
  return res;
}

function inorderTraversal(root) {
  const res = [];
  function traverse(node) {
    if (!node) return;
    traverse(node.left);
    res.push(node.val);
    traverse(node.right);
  }
  traverse(root);
  return res;
}

function postorderTraversal(root) {
  const res = [];
  function traverse(node) {
    if (!node) return;
    traverse(node.left);
    traverse(node.right);
    res.push(node.val);
  }
  traverse(root);
  return res;
}

 在这个实现中,TreeNode类表示树节点,包含一个值val和左右子节点left和right。preorderTraversal、inorderTraversal和postorderTraversal函数分别实现了树的前序、中序和后序遍历。这些函数接受一个根节点root作为参数,并返回一个数组,表示遍历结果。

const 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);

console.log(preorderTraversal(root)); // [1, 2, 4, 5, 3]
console.log(inorderTraversal(root)); // [4, 2, 5, 1, 3]
console.log(postorderTraversal(root)); // [4, 5, 2, 3, 1]

使用这个实现,可以创建一个树,并对其进行前序、中序、后序遍历。例如,可以使用以下代码创建一个包含5个节点的树,并输出树的前序、中序、后序遍历结果:

输出结果分别为:

[1, 2, 4, 5, 3] [4, 2, 5, 1, 3] [4, 5, 2, 3, 1]

 树的层序遍历

树的层序遍历是指按照从上到下、从左到右的顺序依次访问树中的所有节点。也就是说,先访问根节点,然后依次访问第一层、第二层、第三层……直到访问完所有节点。

以下是一个简单的JavaScript实现树的层序遍历的示例代码:     

class TreeNode {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}

function levelOrderTraversal(root) {
  if (!root) return [];
  const queue = [root];
  const res = [];
  while (queue.length) {
    const level = [];
    const size = queue.length;
    for (let i = 0; i < size; i++) {
      const node = queue.shift();
      level.push(node.val);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    res.push(level);
  }
  return res;
}

在这个实现中,TreeNode类表示树节点,包含一个值val和左右子节点left和right。levelOrderTraversal函数实现了树的层序遍历。这个函数接受一个根节点root作为参数,并返回一个二维数组,表示遍历结果。二维数组中的每个子数组表示一层节点的值。

使用这个实现,可以创建一个树,并对其进行层序遍历。例如,可以使用以下代码创建一个包含5个节点的树,并输出树的层序遍历结果:

const 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);

console.log(levelOrderTraversal(root)); // [[1], [2, 3], [4, 5]]

获取树的层级

获取树的层级是指确定树中节点的深度,也就是从根节点到该节点的路径长度。可以使用递归或迭代的方式实现。

以下是一个简单的JavaScript实现获取树的层级的示例代码:

class TreeNode {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}

function getTreeDepth(root) {
  if (!root) return 0;
  const leftDepth = getTreeDepth(root.left);
  const rightDepth = getTreeDepth(root.right);
  return Math.max(leftDepth, rightDepth) + 1;
}

在这个实现中,TreeNode类表示树节点,包含一个值val和左右子节点left和right。getTreeDepth函数实现了获取树的层级。这个函数接受一个根节点root作为参数,并返回一个整数,表示树的深度。

使用这个实现,可以创建一个树,并获取其深度。例如,可以使用以下代码创建一个包含5个节点的树,并输出树的深度:

const 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);

console.log(getTreeDepth(root)); // 3

实现 类数组转数组​​​​​​​

类数组转数组是指将类数组对象转换为真正的数组对象。类数组对象是指具有length属性和按照数字索引访问元素的对象,例如arguments对象和DOM元素集合。可以使用Array.from方法或展开运算符(...)实现类数组转数组。

以下是一个简单的JavaScript实现类数组转数组的示例代码:

function toArray(arrayLike) {
  return Array.from(arrayLike);
  // 或者使用展开运算符
  // return [...arrayLike];
}

在这个实现中,toArray函数接受一个类数组对象arrayLike作为参数,并返回一个真正的数组对象。可以使用Array.from方法或展开运算符将类数组对象转换为数组对象。

使用这个实现,可以将一个类数组对象转换为数组对象。例如,可以使用以下代码将arguments对象转换为数组对象:

function foo() {
  const args = toArray(arguments);
  console.log(args);
}

foo(1, 2, 3); // [1, 2, 3]

实现 DOM转JSON

DOM转JSON是指将DOM节点转换为JSON格式的数据。可以使用递归的方式遍历DOM树,将每个节点转换为一个JSON对象,并将所有JSON对象组合成一个JSON数组。

以下是一个简单的JavaScript实现DOM转JSON的示例代码:

function domToJson(node) {
  const obj = {};
  obj.tagName = node.tagName.toLowerCase();
  obj.attributes = {};
  for (let i = 0; i < node.attributes.length; i++) {
    const attr = node.attributes[i];
    obj.attributes[attr.name] = attr.value;
  }
  obj.children = [];
  for (let i = 0; i < node.children.length; i++) {
    const child = node.children[i];
    obj.children.push(domToJson(child));
  }
  return obj;
}

在这个实现中,domToJson函数接受一个DOM节点node作为参数,并返回一个JSON对象。这个函数使用递归的方式遍历DOM树,将每个节点转换为一个JSON对象,并将所有JSON对象组合成一个JSON数组。

使用这个实现,可以将一个DOM节点转换为JSON格式的数据。例如,可以使用以下代码将一个div元素转换为JSON格式的数据:

const div = document.createElement('div');
div.setAttribute('id', 'myDiv');
div.innerHTML = '<p>Hello, world!</p>';

const json = domToJson(div);
console.log(json);
{
  "tagName": "div",
  "attributes": {
    "id": "myDiv"
  },
  "children": [
    {
      "tagName": "p",
      "attributes": {},
      "children": [
        {
          "tagName": "#text",
          "attributes": {},
          "children": [],
          "text": "Hello, world!"
        }
      ]
    }
  ]
}

实现 JSON转DOM

JSON转DOM是指将JSON格式的数据转换为DOM节点。可以使用递归的方式遍历JSON对象,将每个JSON对象转换为一个DOM节点,并将所有DOM节点组合成一个DOM树。

以下是一个简单的JavaScript实现JSON转DOM的示例代码:

实现 树转数组

function jsonToDom(json) {
  const node = document.createElement(json.tagName);
  for (const attr in json.attributes) {
    node.setAttribute(attr, json.attributes[attr]);
  }
  for (let i = 0; i < json.children.length; i++) {
    const child = json.children[i];
    node.appendChild(jsonToDom(child));
  }
  if (json.text) {
    node.appendChild(document.createTextNode(json.text));
  }
  return node;
}

在这个实现中,jsonToDom函数接受一个JSON对象json作为参数,并返回一个DOM节点。这个函数使用递归的方式遍历JSON对象,将每个JSON对象转换为一个DOM节点,并将所有DOM节点组合成一个DOM树。

使用这个实现,可以将一个JSON格式的数据转换为DOM节点。例如,可以使用以下代码将一个JSON格式的数据转换为DOM节点:

const json = {
  "tagName": "div",
  "attributes": {
    "id": "myDiv"
  },
  "children": [
    {
      "tagName": "p",
      "attributes": {},
      "children": [
        {
          "tagName": "#text",
          "attributes": {},
          "children": [],
          "text": "Hello, world!"
        }
      ]
    }
  ]
};

const div = jsonToDom(json);
document.body.appendChild(div);

实现 数组转树

数组转树是指将一个数组转换为树形结构。通常情况下,数组中的每个元素都代表一个节点,节点之间的关系可以通过元素中的某些属性来表示。可以使用递归的方式遍历数组,将每个节点转换为一个树节点,并将所有树节点组合成一个树形结构。

以下是一个简单的JavaScript实现数组转树的示例代码:

function arrayToTree(arr, parentId) {
  const tree = [];
  for (let i = 0; i < arr.length; i++) {
    const node = arr[i];
    if (node.parentId === parentId) {
      const children = arrayToTree(arr, node.id);
      if (children.length) {
        node.children = children;
      }
      tree.push(node);
    }
  }
  return tree;
}

在这个实现中,arrayToTree函数接受一个数组arr和一个父节点ID parentId作为参数,并返回一个树形结构。这个函数使用递归的方式遍历数组,将每个节点转换为一个树节点,并将所有树节点组合成一个树形结构。

使用这个实现,可以将一个数组转换为树形结构。例如,可以使用以下代码将一个数组转换为树形结构

const arr = [
  { id: 1, name: 'Node 1', parentId: null },
  { id: 2, name: 'Node 2', parentId: 1 },
  { id: 3, name: 'Node 3', parentId: 1 },
  { id: 4, name: 'Node 4', parentId: 2 },
  { id: 5, name: 'Node 5', parentId: 2 },
  { id: 6, name: 'Node 6', parentId: 3 },
  { id: 7, name: 'Node 7', parentId: 3 },
];

const tree = arrayToTree(arr, null);
console.log(tree);

[
  {
    "id": 1,
    "name": "Node 1",
    "parentId": null,
    "children": [
      {
        "id": 2,
        "name": "Node 2",
        "parentId": 1,
        "children": [
          {
            "id": 4,
            "name": "Node 4",
            "parentId": 2,
            "children": []
          },
          {
            "id": 5,
            "name": "Node 5",
            "parentId": 2,
            "children": []
          }
        ]
      },
      {
        "id": 3,
        "name": "Node 3",
        "parentId": 1,
        "children": [
          {
            "id": 6,
            "name": "Node 6",
            "parentId": 3,
            "children": []
          },
          {
            "id": 7,
            "name": "Node 7",
            "parentId": 3,
            "children": []
          }
        ]
      }
    ]
  }
]

实现 对象打平

对象打平是指将一个嵌套的对象转换为一个扁平的对象,其中所有的属性都位于同一层级。通常情况下,嵌套的对象中包含了多个层级,每个层级都包含了一些属性。可以使用递归的方式遍历对象,将每个属性转换为一个扁平的属性,并将所有属性组合成一个扁平的对象。

以下是一个简单的JavaScript实现对象打平的示例代码:

function flattenObject(obj, prefix = '') {
  const flatObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const propName = prefix ? `${prefix}.${key}` : key;
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        Object.assign(flatObj, flattenObject(obj[key], propName));
      } else {
        flatObj[propName] = obj[key];
      }
    }
  }
  return flatObj;
}

在这个实现中,flattenObject函数接受一个嵌套的对象obj和一个前缀prefix作为参数,并返回一个扁平的对象。这个函数使用递归的方式遍历对象,将每个属性转换为一个扁平的属性,并将所有属性组合成一个扁平的对象。

使用这个实现,可以将一个嵌套的对象转换为一个扁平的对象。例如,可以使用以下代码将一个嵌套的对象转换为一个扁平的对象:

const obj = {
  a: {
    b: {
      c: 1,
      d: 2,
    },
    e: 3,
  },
  f: 4,
};

const flatObj = flattenObject(obj);
console.log(flatObj);
{
  "a.b.c": 1,
  "a.b.d": 2,
  "a.e": 3,
  "f": 4
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。