欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹?相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

從事資陽主機(jī)托管,服務(wù)器租用,云主機(jī),網(wǎng)頁空間,空間域名,CDN,網(wǎng)絡(luò)代維等服務(wù)。

遞歸和尾遞歸

簡單的說,遞歸就是函數(shù)自己調(diào)用自己,它做為一種算法在程序設(shè)計(jì)語言中廣泛應(yīng)用。其核心思想是把一個(gè)大型復(fù)雜的問題層層轉(zhuǎn)化為一個(gè)與原問題相似的規(guī)模較小的問題來求解。一般來說,遞歸需要有邊界條件、遞歸前進(jìn)階段和遞歸返回階段。當(dāng)邊界條件不滿足時(shí),遞歸前進(jìn);當(dāng)邊界條件滿足時(shí),遞歸返回。

但是作為一個(gè)合格的程序員,我們也因該知道,遞歸算法相對常用的算法如普通循環(huán)等,運(yùn)行效率較低。因此,應(yīng)該盡量避免使用遞歸,除非沒有更好的算法或者某種特定情況,遞歸更為適合的時(shí)候。在遞歸調(diào)用的過程當(dāng)中系統(tǒng)為每一層的返回點(diǎn)、局部量等開辟了棧來存儲(chǔ),遞歸次數(shù)過多容易造成棧溢出等。

這個(gè)時(shí)候,我們就需要用到尾遞歸,即一個(gè)函數(shù)中所有遞歸形式的調(diào)用都出現(xiàn)在函數(shù)的末尾,對于尾遞歸來說,由于只存在一個(gè)調(diào)用記錄,所以永遠(yuǎn)不會(huì)發(fā)生"棧溢出"錯(cuò)誤。

舉個(gè)例子,我們來實(shí)現(xiàn)一下階乘,如果用普通的遞歸,實(shí)現(xiàn)將是這樣的:

function factorial(n) {
 if (n === 1) return 1;
 return n * factorial(n - 1);
}

factorial(5) // 120

最多需要保存n個(gè)調(diào)用棧,復(fù)雜度 O(n),如果我們使用尾遞歸:

function factorial(n, total) {
 if (n === 1) return total;
 return factorial(n - 1, n * total);
}

factorial(5) // 120

此時(shí)只需要保存一個(gè)調(diào)用棧,復(fù)雜度 O(1) 。通過這個(gè)案例,你是否已經(jīng)慢慢理解其精髓了呢?接下來我將介紹幾個(gè)常用的遞歸應(yīng)用的案例,并在其后實(shí)現(xiàn)本文標(biāo)題剖出的樹的實(shí)現(xiàn)。

遞歸的常用應(yīng)用案例

1. 數(shù)組求和

對于已知數(shù)組arr,求arr各項(xiàng)之和。

function sumArray(arr, total) {
 if(arr.length === 1) {
  return total
 }
 return sum(arr, total + arr.pop())
}

let arr = [1,2,3,4];
sumArray(arr, arr[1]) // 10

該方法給函數(shù)傳遞一個(gè)數(shù)組參數(shù)和初始值,也就是數(shù)組的第一項(xiàng),通過迭代來實(shí)現(xiàn)數(shù)組求和。

2. 斐波那且數(shù)列

斐波那契數(shù)列(Fibonacci sequence),又稱黃金分割數(shù)列,指的是這樣一個(gè)數(shù)列:1、1、2、3、5、8、13、21、34、……在數(shù)學(xué)上,斐波那契數(shù)列以如下被以遞推的方法定義:F(1)=1,F(xiàn)(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在現(xiàn)代物理、準(zhǔn)晶體結(jié)構(gòu)、化學(xué)等領(lǐng)域,斐波納契數(shù)列都有直接的應(yīng)用。接下來我們用js實(shí)現(xiàn)一個(gè)求第n個(gè)斐波那契數(shù)的方法:

// 斐波那契數(shù)列
function factorial1 (n) {
 if(n <= 2){
  return 1
 }
 return factorial1(n-1) + factorial1(n-2)
}

// 尾遞歸優(yōu)化后
function factorial2 (n, start = 1, total = 1) {
 if(n <= 2){
  return total
 }
 return factorial2 (n -1, total, total + start)
}

由尾遞歸優(yōu)化后的函數(shù)可以知道,每一次調(diào)用函數(shù)自身,都會(huì)將更新后的初始值和最終的結(jié)果傳遞進(jìn)去,通過回溯來求得最終的結(jié)果。

3. 階乘

階乘在上文以提到過,如想回顧,請向上翻閱。

4. 省市級聯(lián)多級聯(lián)動(dòng)

省市級聯(lián)多級聯(lián)動(dòng)的方法本質(zhì)是生成結(jié)構(gòu)化的數(shù)據(jù)結(jié)構(gòu),在element或antd中都有對應(yīng)的實(shí)現(xiàn),這里就不做過多介紹了。

5. 深拷貝

深拷貝的例子大家也已經(jīng)司空見慣了,這里只給出一個(gè)簡單的實(shí)現(xiàn)思路:

function clone(target) {
 if (typeof target === 'object') {
  let cloneTarget = Array.isArray(target) ? [] : {};
  for (const key in target) {
   cloneTarget[key] = clone(target[key]);
  }
  return cloneTarget;
 } else {
  return target;
 }
};

6. 爬梯問題

一共有n個(gè)臺(tái)階,每次只能走一個(gè)或兩個(gè)臺(tái)階,問要走完這個(gè)臺(tái)階,一共有多少種走法。

n =1; result = 1 --> 1
n =2; result = 2 --> 11 2
n =3; result = 3 --> 111 12 21
...
如果第一步走1個(gè)臺(tái)階,由以上規(guī)律可以發(fā)現(xiàn)剩下的臺(tái)階有n-1種走法;
如果第一步走2個(gè)臺(tái)階,由以上規(guī)律可以發(fā)現(xiàn)剩下的臺(tái)階有n-2種走法;
則一共有fn(n-1) + fn(n-2) 種走法
function steps(n) {
 if(n <= 1) {
  return 1
 }
 return steps(n-1) + steps(n-2)
}

7. 對象數(shù)據(jù)格式化

這道題是本人曾經(jīng)面試阿里的一道筆試題,問題是如果服務(wù)器返回了嵌套的對象,對象鍵名大小寫不確定,如果統(tǒng)一讓鍵名小寫。

let obj = {
 a: '1',
 b: {
  c: '2',
  D: {
   E: '3'
  }
 }
}
轉(zhuǎn)化為如下:
let obj = {
 a: '1',
 b: {
  c: '2',
  d: {
   e: '3'
  }
 }
}

// 代碼實(shí)現(xiàn)
function keysLower(obj) {
 let reg = new RegExp("([A-Z]+)", "g");
 for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
   let temp = obj[key];
   if (reg.test(key.toString())) {
    // 將修改后的屬性名重新賦值給temp,并在對象obj內(nèi)添加一個(gè)轉(zhuǎn)換后的屬性
    temp = obj[key.replace(reg, function (result) {
     return result.toLowerCase()
    })] = obj[key];
    // 將之前大寫的鍵屬性刪除
    delete obj[key];
   }
   // 如果屬性是對象或者數(shù)組,重新執(zhí)行函數(shù)
   if (typeof temp === 'object' || Object.prototype.toString.call(temp) === '[object Array]') {
    keysLower(temp);
   }
  }
 }
 return obj;
};

具體過程和思路在代碼中已經(jīng)寫出了注釋,感興趣可以自己研究一下。

8. 遍歷目錄/刪除目錄

我們這里使用node來實(shí)現(xiàn)刪除一個(gè)目錄,用現(xiàn)有的node API確實(shí)有刪除目錄的功能,但是目錄下如果有文件或者子目錄,fs.rmdir && fs.rmdirSync 是不能將其刪除的,所以要先刪除目錄下的文件,最后再刪除文件夾。

function deleteFolder(path) {
 var files = [];
 if(fs.existsSync(path)) { // 如果目錄存在
  files = fs.readdirSync(path);
  files.forEach(function(file,index){
   var curPath = path + "/" + file;
   if(fs.statSync(curPath).isDirectory()) { // 如果是目錄,則遞歸
    deleteFolder(curPath);
   } else { // 刪除文件
    fs.unlinkSync(curPath);
   }
  });
  fs.rmdirSync(path);
 }
}

9. 繪制分形圖形

通過遞歸,我們可以在圖形學(xué)上有更大的自由度,但是請記住,并不是最好的選擇。

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

我們可以借助一些工具和遞歸的思想,實(shí)現(xiàn)如上的分形圖案。

10. 扁平化數(shù)組Flat

數(shù)組拍平實(shí)際上就是把一個(gè)嵌套的數(shù)組,展開成一個(gè)數(shù)組,如下案例:

let a = [1,2,3, [1,2,3, [1,2,3]]]
// 變成
let a = [1,2,3,1,2,3,1,2,3]
// 具體實(shí)現(xiàn)
function flat(arr = [], result = []) {
  arr.forEach(v => {
    if(Array.isArray(v)) {
      result = result.concat(flat(v, []))
    }else {
      result.push(v)
    }
  })
  return result
}

flat(a)

當(dāng)然這只是筆者實(shí)現(xiàn)的一種方式,更多實(shí)現(xiàn)方式等著你去探索。

用遞歸畫一棵自定義風(fēng)格的結(jié)構(gòu)樹

通過上面的介紹,我想大家對遞歸及其應(yīng)用已經(jīng)有一個(gè)基本的概念,接下來我將一步步的帶大家用遞歸畫一棵結(jié)構(gòu)樹。

效果圖:

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

該圖形是根據(jù)目錄結(jié)構(gòu)生成的目錄樹圖,在很多應(yīng)用場景中被廣泛使用,接下來我們就來看看他的實(shí)現(xiàn)過程吧:

const fs = require('fs')
const path = require('path')
// 遍歷目錄/生成目錄樹
function treeFolder(path, flag = '|_') {
  var files = [];
  
  if(fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function(file,index){
      var curPath = path + "/" + file;
      if(fs.statSync(curPath).isDirectory()) { // recurse
        // obj[file] = treeFolder(curPath, {});
        console.log(flag, file)
        treeFolder(curPath, '  ' + flag)
      } else {
        // obj['--'] = file
        console.log(flag, file)
      }
    })
    // return obj
  }
}

treeFolder(path.resolve(__dirname, './test'))

test為我們建的測試目錄,如下:

怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹

看完上述內(nèi)容,你們掌握怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

網(wǎng)站欄目:怎么在javascript中利用遞歸繪制一個(gè)結(jié)構(gòu)樹
文章網(wǎng)址:http://chinadenli.net/article0/iegdio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、虛擬主機(jī)、響應(yīng)式網(wǎng)站網(wǎng)站建設(shè)、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)
日韩免费国产91在线| 国产一级精品色特级色国产| 欧美综合色婷婷欧美激情| 国产一区二区熟女精品免费| 精品欧美日韩一区二区三区 | 国产伦精品一区二区三区高清版| 国产一级精品色特级色国产| 国产乱人伦精品一区二区三区四区| 91福利免费一区二区三区| 久久99夜色精品噜噜亚洲av | 精品国产丝袜一区二区| 日本午夜精品视频在线观看| 亚洲天堂久久精品成人| 伊人网免费在线观看高清版| 黄片免费在线观看日韩| 美国欧洲日本韩国二本道| 很黄很污在线免费观看| 欧美日韩免费观看视频| 欧美成人久久久免费播放| 国产日韩欧美专区一区| 成人午夜爽爽爽免费视频| 不卡中文字幕在线免费看| 欧美乱视频一区二区三区| 东京干男人都知道的天堂| 中文字幕乱码一区二区三区四区| 91香蕉国产观看免费人人| 精品久久久一区二区三| 欧美区一区二在线播放| 国产av大片一区二区三区| 国产亚洲精品俞拍视频福利区| 美女黄片大全在线观看| 国产精品亚洲二区三区| 老鸭窝精彩从这里蔓延| 亚洲熟女国产熟女二区三区| 亚洲午夜av久久久精品| 少妇人妻一级片一区二区三区| 懂色一区二区三区四区| 国产精品亚洲一级av第二区| 日韩成人高清免费在线| 黄色污污在线免费观看| 国产成人精品一区二区三区|