1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      怎么使用Scala語言

      這篇文章主要講解了“怎么使用Scala語言”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么使用Scala語言”吧!

      創(chuàng)新互聯(lián)是專業(yè)的鹽亭網(wǎng)站建設(shè)公司,鹽亭接單;提供網(wǎng)站制作、做網(wǎng)站,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行鹽亭網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

      為什么遞歸會受到忽視

      為 了回答這一問題,必須先說到編程范式。在所有的編程范式中,面向?qū)ο缶幊蹋∣bject-Oriented  Programming)無疑是***的贏家。看看網(wǎng)上的招聘啟事,無一例外,會要求應(yīng)聘者熟練掌握面向?qū)ο缶幊獭5鋵?shí)面向?qū)ο缶幊滩⒉皇且环N嚴(yán)格意義上  的編程范式,嚴(yán)格意義上的編程范式分為:命令式編程(Imperative Programming)、函數(shù)式編程(Functional  Programming)和邏輯式編程(Logic  Programming)。面向?qū)ο缶幊讨皇巧鲜鰩追N范式的一個(gè)交叉產(chǎn)物,更多的還是繼承了命令式編程的基因。遺憾的是,在長期的教學(xué)過程中,只有命令式   編程得到了強(qiáng)調(diào),那就是程序員要告訴計(jì)算機(jī)應(yīng)該怎么做,而不是告訴計(jì)算機(jī)做什么。而遞歸則通過靈巧的函數(shù)定義,告訴計(jì)算機(jī)做什么。因此在使用命令式編程思   維的程序中,不得不說,這是現(xiàn)在多數(shù)程序采用的編程方式,遞歸出鏡的幾率很少,而在函數(shù)式編程中,大家可以隨處見到遞歸的方式。下面,我們就通過實(shí)例,為  大家展示遞歸如何作為一種普遍方式,來解決編程問題的。

      一組簡單的例子

      如何為一組整數(shù)數(shù)列求和?按照通常命令式編程的思 維,我們會采用循環(huán),依次遍歷列表中的每個(gè)元素進(jìn)行累加,最終給出求和結(jié)果。這樣的程序不難寫,稍  微具備一點(diǎn)編程經(jīng)驗(yàn)的人在一分鐘之內(nèi)就能寫出來。這次我們換個(gè)思維,如何用遞歸的方式求和?為此,我們不妨把問題簡化一點(diǎn),假設(shè)數(shù)列包含 N  個(gè)數(shù),如果我們已經(jīng)知道了后續(xù) N – 1 個(gè)數(shù)的和,那么整個(gè)數(shù)列的和即為***個(gè)數(shù)加上后續(xù) N – 1 個(gè)數(shù)的和,依此類推,我們可以以同樣的方式為  N – 1  個(gè)數(shù)繼續(xù)求和,直到數(shù)列為空,顯然,空數(shù)列的和為零。聽起來復(fù)雜,事實(shí)上我們可以用一句話來總結(jié):一個(gè)數(shù)列的和即為數(shù)列中的***個(gè)數(shù)加上由后續(xù)數(shù)字組成的  數(shù)列的和。現(xiàn)在,讓我們用 Scala 語言把這個(gè)想法表達(dá)出來。

      清單 1. 數(shù)列求和

      //xs.head 返回列表里的頭元素,即***個(gè)元素 //xs.tail 返回除頭元素外的剩余元素組成的列表 def sum(xs: List[Int]): Int =  if (xs.isEmpty) 0 else xs.head + sum(xs.tail)

      大家可以看到,我們只使用一行程序,就將上面求和的方法表達(dá)出來了,而且這一行程序看上去簡單易懂。盡量少寫代碼,這也是 Scala  語言的設(shè)計(jì)哲學(xué)之一,較少的代碼量意味著寫起來更加容易,讀起來更加易懂,同時(shí)代碼出錯(cuò)的概率也會降低。同樣的程序,使用 Scala  語言寫出的代碼量通常會比 Java 少一半甚至更多。

      上述這個(gè)數(shù)列求和的例子并不是特別的,它代表了遞歸對于列表的一種普遍的處理方式,即對一個(gè)列表的操作,可轉(zhuǎn)化為對***個(gè)元素,及剩余列表的相同操 作。比如我們可以用同樣的方式求一個(gè)數(shù)列中的***值。我們假設(shè)已經(jīng)知道了除***個(gè)元素外剩余數(shù)列的***值,那么整個(gè)數(shù)列的***值即為***個(gè)元素和剩余數(shù)列 ***值中的大者。這里需要注意的是對于一個(gè)空數(shù)列求***值是沒有意義的,所以我們需要向外拋出一個(gè)異常。當(dāng)數(shù)列只包含一個(gè)元素時(shí),***值就為這個(gè)元素本 身,這種情況是我們這個(gè)遞歸的邊界條件。一個(gè)遞歸算法,必須要有這樣一個(gè)邊界條件,否則會一直遞歸下去,形成死循環(huán)。

      清單 2. 求***值

      def max(xs: List[Int]): Int = {    if (xs.isEmpty)      throw new java.util.NoSuchElementException    if (xs.size == 1)      xs.head    else      if (xs.head > max(xs.tail)) xs.head else max(xs.tail) }v

      同樣的方式,我們也可以求一個(gè)數(shù)列中的最小值,作為一個(gè)練習(xí),讀者可下去自行實(shí)現(xiàn)。

      讓我們再看一個(gè)例子:如何反轉(zhuǎn)一個(gè)字符串?比如給定一個(gè)字符串"abcd",經(jīng)過反轉(zhuǎn)之后變?yōu)?nbsp;"dcba"。同樣的,我們可以做一個(gè)大膽的假設(shè),假設(shè)后續(xù)字符串已經(jīng)反轉(zhuǎn)過來,那么接上***個(gè)字符,整個(gè)字符串就反轉(zhuǎn)過來了。對于一個(gè)只有一個(gè)字符的字符串,不需要反轉(zhuǎn),這是我們這個(gè)遞歸算法的邊界條件。程序?qū)崿F(xiàn)如下:

      清單 3. 反轉(zhuǎn)字符串

      def reverse(xs: String): String = if (xs.length == 1) xs else reverse(xs.tail) + xs.head

      ***一個(gè)例子是經(jīng)典的快速排序,讀者可能會覺得這個(gè)例子算不上簡單,但是我們會看到,使用遞歸的方式,再加上 Scala 簡潔的語言特性,我們只需要短短幾行程序,就可以實(shí)現(xiàn)快速排序算法。 快速排序算法的核心思想是:在一個(gè)無序列表中選擇一個(gè)值,根據(jù)該值將列表分為兩部分,比該值小的那一部分排在前面,比該值大的部分排在后面。對于這兩部分 各自使用同樣的方式進(jìn)行排序,直到他們?yōu)榭眨@然,我們認(rèn)為一個(gè)空的列表即為一個(gè)排好序的列表,這就是這個(gè)算法中的邊界條件。為了方便起見,我們選擇*** 個(gè)元素作為將列表分為兩部分的值。程序?qū)崿F(xiàn)如下:

      清單 4. 快速排序

      def quickSort(xs: List[Int]): List[Int] = {    if (xs.isEmpty) xs    else      quickSort(xs.filter(x=>xx>xs.head)) }

      當(dāng)然,為了使程序更加簡潔,作者在這里使用了列表中的一些方法:給列表增加一個(gè)元素,連接兩個(gè)列表以及過濾一個(gè)列表,并在其中使用了 lambda 表達(dá)式。但這一切都使程序變得更符合算法的核心思想,更加易讀。

      尾遞歸

      從上面的例子中我們可以看到,使用遞歸方式寫出的程序通常通俗易懂,這其實(shí)代表這兩種編程范式的不同,命令式編程范式傾向于使用循環(huán),告訴計(jì)算機(jī)怎 么做,而函數(shù)式編程范式則使用遞歸,告訴計(jì)算機(jī)做什么。習(xí)慣于命令式編程范式的程序員還有一個(gè)擔(dān)憂:相比循環(huán),遞歸不是存在效率問題嗎?每一次遞歸調(diào)用, 都會分配一個(gè)新的函數(shù)棧,如果遞歸嵌套很深,容易出現(xiàn)棧溢出的問題。比如下面計(jì)算階乘的遞歸程序:

      清單 5. 遞歸求階乘

      def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n - 1)

      當(dāng)遞歸調(diào)用 n – 1的階乘時(shí),由于需要保存前面的 n,必須分配一個(gè)新的函數(shù)棧,這樣當(dāng) n很大時(shí),函數(shù)棧將很快被耗盡。然而尾遞歸能幫我們解決這個(gè)問題,所謂尾遞歸是指在函數(shù)調(diào)用的***一步,只調(diào)用該遞歸函數(shù)本身,此時(shí),由于無需記住其他變量,當(dāng)前的函數(shù)棧可以被重復(fù)使用。上面的程序只需稍微改造一下,既可以變成尾遞歸式的程序,在效率上,和循環(huán)是等價(jià)的。

      清單 6. 尾遞歸求階乘

      def factorial(n: Int): Int = {    @tailrec    def loop(acc: Int, n: Int): Int =      if (n == 0) acc else loop(n * acc, n - 1)      loop(1, n) }

      在上面的程序中,我們在階乘函數(shù)內(nèi)部定義了一個(gè)新的遞歸函數(shù),該函數(shù)***一步要么返回結(jié)果,要么調(diào)用該遞歸函數(shù)本身,所以這是一個(gè)尾遞歸函數(shù)。該函數(shù)多出一個(gè)變量 acc,每次遞歸調(diào)用都會更新該變量,直到遞歸邊界條件滿足時(shí)返回該值,即為***的計(jì)算結(jié)果。這是一種通用的將非尾遞歸函數(shù)轉(zhuǎn)化為尾遞歸函數(shù)的方法,大家可多加練習(xí),掌握這一方法。對于尾遞歸,Scala 語言特別增加了一個(gè)注釋 @tailrec,該注釋可以確保程序員寫出的程序是正確的尾遞歸程序,如果由于疏忽大意,寫出的不是一個(gè)尾遞歸程序,則編譯器會報(bào)告一個(gè)編譯錯(cuò)誤,提醒程序員修改自己的代碼。

      一道面試題

      也許有的讀者看了上面的例子后,還是感到不能信服:雖然使用遞歸會讓程序變得簡潔易懂,但我用循環(huán)也一樣可以實(shí)現(xiàn),大不了多幾行代碼而已,而且我還 不用知道什么尾遞歸,寫出的程序就是效率***的。那我們一起來看看下面這個(gè)問題:有趣的零錢兌換問題。題目大致如下:假設(shè)某國的貨幣有若干面值,現(xiàn)給一張 大面值的貨幣要兌換成零錢,問有多少種兌換方式。這個(gè)問題經(jīng)常被各大公司作為一道面試題,不知難倒了多少同學(xué),下面我給出該問題的遞歸解法,讀者們可以試 試該問題的非遞歸解法,看看從程序的易讀性,及代碼數(shù)量上,兩者會有多大差別。該問題的遞歸解法思路很簡單:首先確定邊界條件,如果要兌換的錢數(shù)為  0,那么返回 1,即只有一種兌換方法:沒法兌換。這里要注意的是該問題計(jì)算所有的兌換方法,無法兌換也算一種方法。如果零錢種類為 0 或錢數(shù)小于  0,沒有任何方式進(jìn)行兌換,返回  0。我們可以把找零的方法分為兩類:使用不包含***枚硬幣(零錢)所有的零錢進(jìn)行找零,使用包含***枚硬幣(零錢)的所有零錢進(jìn)行找零,兩者之和即為所有 的找零方式。***種找零方式總共有 countChange(money, coins.tail)種,第二種找零方式等價(jià)為對于 money – conins.head進(jìn)行同樣的兌換,則這種兌換方式有 countChange(money - coins.head, coins)種,兩者之和即為所有的零錢兌換方式。

      清單 7. 零錢兌換問題的遞歸解法

      def countChange(money: Int, coins: List[Int]): Int = {   if (money == 0)     1   else if (coins.size == 0 || money < 0)     0   else     countChange(money, coins.tail) + countChange(money - coins.head, coins) }

      感謝各位的閱讀,以上就是“怎么使用Scala語言”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對怎么使用Scala語言這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!


      文章題目:怎么使用Scala語言
      當(dāng)前網(wǎng)址:http://www.ef60e0e.cn/article/gsoije.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        成都市| 高安市| 金坛市| 钦州市| 郑州市| 鹤峰县| 龙江县| 板桥市| 于都县| 慈利县| 宣汉县| 张家口市| 鄱阳县| 冷水江市| 刚察县| 永吉县| 酒泉市| 连江县| 噶尔县| 余干县| 开封县| 得荣县| 博湖县| 博兴县| 桐柏县| 赤峰市| 迁安市| 上虞市| 高邑县| 界首市| 蒙山县| 林芝县| 岐山县| 思茅市| 门源| 万安县| 江西省| 平凉市| 万山特区| 泌阳县| 合阳县|