#
通常,你需要獲得當前日期和計算一些其他的日期,例如,你的程序可能需要判斷一個月的第一天或者最后一天。你們大部分人大概都知道怎樣把日期進行分割
(年、月、日等),然后僅僅用分割出來的年、月、日等放在幾個函數中計算出自己所需要的日期!在這篇文 章里,我將告訴你如何使用DATEADD和
DATEDIFF函數來計算出在你的程序中可能你要用到的一些不同日期。
在使用本文中的例子之前,你必須注意以下的問題。大部
分可能不是所有例子在不同的機器上執行的結果可能不一樣,這完全由哪一天是一個星期的第一天這個設置決定。第一天(DATEFIRST)設定決定了你的系
統使用哪一天作為一周的第一天。所有以下的例 子都是以星期天作為一周的第一天來建立,也就是第一天設置為7。假如你的第一天設置不一樣,你可能需要調整
這些例子,使它和不同的第一天設置相符合。你可以通過@@DATEFIRST函數來檢查第一天設置。
為了理解這些例子,
我們先復習一下DATEDIFF和DATEADD函數。DATEDIFF函數計算兩個日期之間的小時、天、周、月、年等時間間隔總數。DATEADD函數
計算一個日期通過給時間間隔加減來獲得一個新的日期。要了解更多的DATEDI FF和DATEADD函數以及時間間隔可以閱讀微軟聯機幫助。
使用DATEDIFF和DATEADD函數來計算日期,和本來從當前日期轉換到你需要的日期的考慮方法有點不同。你必須從時間間隔這個方面來考慮。比
如,從當前日期到你要得到的日期之間有多少時間間隔,或者,從今天到某一天(比如1900-1-1)之間有多少時間間隔,等等。理解怎樣著眼于時間間隔有
助于你輕松的理解我的不同的日期計算例子。
一個月的第一天
第一個例子,我將告訴你如何從當前日期去這個月的最后一天。請注意:這個例子以及這篇文章中的其他例子都將只使用DATEDIFF和DATEADD函數來計算我們想要的日期。每一個例子都將通過計算但前的時間間隔,然后進行加減來得到想要計算的日期。
這是計算一個月第一天的SQL 腳本:
SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
我們把這個語句分開來看看它是如何工作的。最核心的函數是getdate(),大部分人都知道這個是返回當前的日期和時間的函數。下一個執行的函數
DATEDIFF(mm,0,getdate())是計算當前日期和“1900-01-01 00:00:00.000”這個日期之間的月數。記住:時期
和時間變量和毫秒一樣是從“1900-01-01 00:00:00.000”開始計算的。這就是為什么你可以在DATEDIFF函數中指定第一個時間表
達式為“0”。下一個函數是DATEADD,增加當前日期到“1900-01-01”的月數。通過增加預定義的日期“1900-01-01”和當前日期的
月數,我們可以獲得這個月的第一天。另外,計算出來的日期的時間部分將會是“00:00:00.000”。
這個計算的技巧是先計算當前日期到“1900-01-01”的時間間隔數,然后把它加到“1900-01-01”上來獲得特殊的日期,這個技巧可以用來計算很多不同的日期。下一個例子也是用這個技巧從當前日期來產生不同的日期。
本周的星期一
這里我是用周(wk)的時間間隔來計算哪一天是本周的星期一。
SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)
一年的第一天
現在用年(yy)的時間間隔來顯示這一年的第一天。
SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
季度的第一天
假如你要計算這個季度的第一天,這個例子告訴你該如何做。
SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)
當天的半夜
曾經需要通過getdate()函數為了返回時間值截掉時間部分,就會考慮到當前日期是不是在半夜。假如這樣,這個例子使用DATEDIFF和DATEADD函數來獲得半夜的時間點。
SELECT DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)
深入DATEDIFF和DATEADD函數計算
你可以明白,通過使用簡單的DATEDIFF和DATEADD函數計算,你可以發現很多不同的可能有意義的日期。
目前為止的所有例子只是僅僅計算當前的時間和“1900-01-01”之間的時間間隔數量,然后把它加到“1900-01-01”的時間間隔上來計算出
日期。假定你修改時間間隔的數量,或者使用不同的時間間隔來調用DATEADD函數,或者減去時間間隔而不是增加,那么通過這些小的調整你可以發現和多不
同的日期。
這里有四個例子使用另外一個DATEADD函數來計算最后一天來分別替換DATEADD函數前后兩個時間間隔。
上個月的最后一天
這是一個計算上個月最后一天的例子。它通過從一個月的最后一天這個例子上減去3毫秒來獲得。有一點要記住,在Sql Server中時間是精確到3毫秒。這就是為什么我需要減去3毫秒來獲得我要的日期和時間。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))
計算出來的日期的時間部分包含了一個Sql Server可以記錄的一天的最后時刻(“23:59:59:997”)的時間。
去年的最后一天
連接上面的例子,為了要得到去年的最后一天,你需要在今年的第一天上減去3毫秒。
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
本月的最后一天
現在,為了獲得本月的最后一天,我需要稍微修改一下獲得上個月的最后一天的語句。修改需要給用DATEDIFF比較當前日期和“1900-01-01”
返回的時間間隔上加1。通過加1個月,我計算出下個月的第一天,然后減去3毫秒,這樣就計算出了這個月的最后一天。這是計算本月最后一天的SQL腳本。
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))
本年的最后一天
你現在應該掌握這個的做法,這是計算本年最后一天腳本
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))。
本月的第一個星期一
好了,現在是最后一個例子。這里我要計算這個月的第一個星期一。這是計算的腳本。
select DATEADD(wk, DATEDIFF(wk,0,
dateadd(dd,6-datepart(day,getdate()),getdate())
), 0)
在這個例子里,我使用了“本周的星期一”的腳本,并作了一點點修改。修改的部分是把原來腳本中“getdate()”部分替換成計算本月的第6天,在計算中用本月的第6天來替換當前日期使得計算可以獲得這個月的第一個星期一。
總結
我希望這些例子可以在你用DATEADD和DATEDIFF函數計算日期時給你一點啟發。通過使用這個計算日期的時間間隔的數學方法,我發現為了顯示兩
個日期之間間隔的有用歷法是有價值的。注意,這只是計算出這些日期的一種方法。要牢記,還有很多方法 可以得到相同的計算結果。假如你有其他的方法,那很
不錯,要是你沒有,我希望這些例子可以給你一些啟發,當你要用DATEADD和DATEDIFF函數計算你程序可能要用到的日期時。
附錄,其他日期處理方法
1)去掉時分秒
declare @ datetime
set @ = getdate() --’2003-7-1 10:00:00’
SELECT @,DATEADD(day, DATEDIFF(day,0,@), 0)
2)顯示星期幾
select datename(weekday,getdate())
3)如何取得某個月的天數
declare @m int
set @m=2 --月份
select datediff(day,’2003-’+cast(@m as varchar)+’-15’ ,’2003-’+cast(@m+1 as varchar)+’-15’)
另外,取得本月天數
select datediff(day,cast(month(GetDate()) as varchar)+’-’+cast(month(GetDate()) as varchar)+’-15’ ,cast(month(GetDate()) as varchar)+’-’+cast(month(GetDate())+1 as varchar)+’-15’)
或者使用計算本月的最后一天的腳本,然后用DAY函數區最后一天
SELECT Day(dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0)))
4)判斷是否閏年:
SELECT case day(dateadd(mm, 2, dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)))) when 28 then ’平年’ else ’閏年’ end
或者
select case datediff(day,datename(year,getdate())+’-02-01’,dateadd(mm,1,datename(year,getdate())+’-02-01’))
when 28 then ’平年’ else ’閏年’ end
5)一個季度多少天
declare @m tinyint,@time smalldatetime
select @m=month(getdate())
select @m=case when @m between 1 and 3 then 1
when @m between 4 and 6 then 4
when @m between 7 and 9 then 7
else 10 end
select @time=datename(year,getdate())+’-’+convert(varchar(10),@m)+’-01’
select datediff(day,@time,dateadd(mm,3,@time))
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses. If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed.
The container must guarantee that servlets marked with lower integers
are loaded before servlets marked with higher integers. The container
may choose the order of loading of servlets with the same
load-on-start-up value.
SOA現在正熱得"燙手"。
對于SOA,目前我聽到有兩種說法:一種講它是"顛覆性的革命架構",一種是"謹慎觀望"。但無疑,SOA最近幾年發展得非常快,各主要軟件廠商紛紛高調跟進,關于SOA的報道可以說是不絕于耳。對"SOA熱",程序員們有的興奮和期待,有的則感到困惑,最近我在金蝶中間件于廣州、上海等城市舉行的"Java俱樂部"上和程序員們交流時,他們或是以一種朝圣者的表情說:"以前面向對象的技術過時了,SOA時代來了",或者一再懇切地追問我:"SOA到底是什么?作用是什么?"
那么,SOA是什么?到底能解決什么問題、解決得怎樣?我們和客戶都準備好了嗎?我給出的答案是"Just Processing,SOA-現在進行中"。
SOA到底是什么?
SOA(Service-Oriented Architecture)的定義是面向服務的架構,就是說將軟件按照功能設計成一個個服務,這些服務用標準的方式定義接口、并通過標準的協議進行調用。SOA所定義的接口和調用方式是獨立于編程語言和運行平臺的,廣義上講SOA可以基于不同的底層技術實現,比如CORBA和Web Services。但CORBA由于過于復雜和臃腫已很少使用,所以目前所說的SOA絕大多數是基于Web Services技術實現。在Web Services的實現方式下,SOA服務的接口用XML進行定義。
在SOA架構下,軟件開發從業務流程分析開始,使用組件化業務建模的方法識別和分析各種業務模型,將各種實踐融入其中,在這個基礎上建立用例,用例直接產生BPEL,這些BPEL則可以被融入一個服務整合框架中,其描述了各種服務的信息,從而把ESB上的各個模塊統一起來,形成一個巨大的服務倉。
這樣,SOA甚至是所有軟件人員的一個夢:將中間層再進行抽離,在中間層作一個跨技術架構的元數據和業務邏輯,使之成為跨技術架構的、可長期繼承、并不斷積累的企業業務庫和最寶貴的信息資產,也就是面向服務的組件庫,而且這個服務組件庫也可以被其它企業復用,且不依賴于任何一種技術架構。夸張一點說,如果所有軟件企業都使用SOA架構,那么世界軟件業將會發生徹底的改變。顯然,這樣一個框架不是一種產品,也不僅僅是一種技術,而是一種解決問題的方法論。
SOA可能應用的兩個場景及現有問題
那么,SOA要解決的問題是什么?我認為,從技術本質上講,SOA可能應用于兩個場景:第一種是業務互通互聯;第二種是封閉交易系統,即將元數據和業務邏輯抽離,形成可復用。舉個例子,在第一種場景中,當不同企業之間的業務需要相互調用,這時就可能采用SOA技術;在第二種場景中,在企業內部需要將系統進行遷移時,利用SOA技術定義的原有數據和業務流程,可以很快完成。
無疑,SOA是一個偉大的思想,它試圖定義一個大家(各種軟件廠商)都"認"的、都"遵循"的法則,大家都使用這樣的方法來進行互聯互通,從而實現無界限的聯通,以及服務組件庫的繼承和復用,解放無效和重復勞動。打一個不那么恰當的比喻,就像人類的語言一樣。SOA或許就像《圣經》中那個著名的"通天塔"的故事:人們用同一種語言交流產生的威力是如此之大,以至于他們在巴比倫幾乎要修成一個"通天塔",直達上帝所在的天庭。
但是,在SOA應用的兩個場景中,現存的問題同樣也是明顯的:
第一種場景:業務互聯互通,就是應用系統互聯。業務互聯,與其說是技術問題,不如講是業務問題,例如ERP、CRM的異步整合,數據層面整合都不能很好將兩個系統整合,SOA僅僅是一種實現工具之一,整合效果并不會好不到那里去。我們可以說,在沒有其他選項之前,SOA是一種最"不壞"的方式,但它并不能解決所有的問題,實際上EAI的牽涉面很廣,而我們知道,有些問題并不是單純靠技術就能解決的。
第二種場景:封閉交易系統,缺點是性能慢,而且基于Web Services的交易沒有形成明確的規范。使用XML作信息交互比較慢是大家都承認的,性能問題將對SOA的發展造在一定的阻力。同時SOA規范本身沒有完善,比如Transaction規范還在不斷完善,而且Web Service多年來收效甚微。總的來說,SOA現在還處在一個發展階段,很多標準還在制定,不同廠商間還存在不兼容的現象,因此SOA還不能說已經是一個成熟的技術,還需要時間的檢驗,還在"進行中"。當然,金蝶中間件作為JCP組織成員,也會推動SOA規范在J2EE平臺上的實現。
中國用戶的現實選擇之惑
在憧憬SOA技術可能帶來的前景之余,我們不得不回過頭來冷靜地說:SOA和我們大家的共同客戶――中國企業還有距離。
中國信息化進程與歐美不同,大量的基礎業務系統還沒建立起來,整合需求并不如想象的那么大。從我們對客戶的了解,發現很少有客戶有SOA的需求。簡單地總結就是,互通無基礎,以新建系統為主,需求并不強烈。而歐美市場大量業務系統已建立起來需要整合,從這個角度講,SOA是適用于他們的。同時,在成功案例極少的前提下,SOA還處于培育期,新建封閉交易系統使用SOA技術還是有一定風險的。
一項新技術需要市場的消化,大型企業出于保護企業投資,不會輕易地轉移到新的技術平臺;而即使像J2EE這樣成熟的技術經過了這么多年的發展,也不敢說占有統治地位的市場份額。SOA還需要整個IT界的用戶和供應商共同促進。
中國信息化需要什么樣的技術架構、能夠接受什么樣的成本價位?這不僅僅是我們的客戶需要考慮,我們軟件廠商要比客戶考慮得更清楚、更進一步。在這個充滿變數的激烈競爭市場,只有冷靜務實才能生存、發展。
From:http://blog.csdn.net/Apusicyuan/archive/2007/03/16/1531424.aspx
解析SOA十大設計原則 公共接口要明確界限
作者: 佚名, 出處:CSDN, 責任編輯: 包春林,
2008-04-23 05:00
日前國外網站報道介紹了面向服務架構(SOA)的基本原則,提出了公共接口與內部實現要有明確界限等原則。雖然這些原則并不是絕對的真理,但可作為一個應用開發參考。
一、明確的邊界
通過跨越定義明確的邊界進行顯式消息傳遞,服務得以彼此交互。有時候,跨越服務邊界可能要耗費很大的成本,這要視地理、信任或執行因素而定。邊界是指服務的公共接口與其內部專用實現之間的界線。服務的邊界通過 WSDL 發布,可能包括說明特定服務之期望的聲明。
二、服務共享和約和架構,不是類
服務交互應當只以服務的策略、架構和基于合約的行為為基礎。服務的合約通常使用 WSDL 定義,而服務聚合的合約則可以使用 BPEL 定義(進而,對聚合的每個服務使用 WSDL)。服務使用者將依靠服務的合約來調用服務及與服務交互。鑒于這種依賴性,服務合約必須長期保持穩定。在利用 XML 架構 (xsd:any) 和 SOAP 處理模型(可選標頭)的可擴展性的同時,合約的設計應盡可能明確。
三、策略驅動
盡管它往往被認為是最不為人所了解的原則,但對于實現靈活的 Web 服務,它或許是最有力的。單純依靠 WSDL 無法交流某些業務交互要求。可以使用策略表達式將結構兼容性(交流的內容)與語義兼容性(如何交流消息或者將消息交流給誰)分隔開來。
四、自治
服務是獨立進行部署、版本控制和管理的實體。開發人員應避免對服務邊界之間的空間進行假設,因為此空間比邊界本身更容易改變。
五、采用可傳輸的協議格式,而不是API
通常,服務提供商基于某種傳輸協議(例如HTTP)提供服務,而服務消費者只能通過另一種不同的協議(比如MQ)通信。因此,也許需要在服務提供商與消費者之間建立一座異步起動同步運行的連接橋梁,超越HTTP和Java Messaging Service消息服務(JMS)等協議.從技術角度講,Java Messaging Service消息服務(JMS)并不是一種傳輸協議,而是一組供應商中立(vendor-neutral)的通信APIs。
六、面向文檔
消息被構造為“純文本的”XML文檔(換句話說,數據的格式只對XML有意義)。 消息通常用于傳輸業務文檔,比如購買訂單、發票和提單。這種交互類型與同步消息排隊系統的兼容性很好,比如MQ Series、MSMQ、JMS、TIBCO、IMS等等。
七、松耦合
服務之間要求最小的依賴性,只要求它們之間能夠相互知曉。
八、符合標準
當通過Web的服務實現時,最原始的(基本的)面向服務的架構(SOA)的模型僅僅提供了很低程度上的關于可靠性、安全性以及事務管理的標準化機制。第二代的技術條件和框架,如WS-ReliableMessaging規范、 WS-Security規范和WS-Coordination規范 (與WS-AtomicTransaction規范和WS-BusinessActivity規范相聯系),它們試圖以工業標準的方式定位存在的缺陷。
九、獨立軟件供應商
向SOA的轉變正在深刻改變了經濟現實。客戶們會期待更合理的費用以及不必重新進行投資就能改進業務的能力。因此,獨立軟件供應商沒有選擇,只能使自己的業務更加靈活,以期讓自己的客戶也變得同樣靈活。于是,面向服務不僅是簡單的在現有的、緊耦合的、復雜的、不靈活的以及非組件化的業務功能上添加基于標準的接口。更重要的是,為了兌現SOA的承諾,獨立軟件供應商必須改變他們構建、打包、銷售、交付、管理和支持自身產品的方式。
十、元數據驅動
開發元數據本身并不是元數據驅動應用程序的本意。使用元數據來驅動服務在系統邊界的傳播是一個更為正確的方法。
一個事務處理的屬性有:Required,RequiresNew,Mandatory,NotSupported,Supports,Never.
1、Required:當客戶端運行一個事務處理并調用EJB的一個方法,這個方法執行客戶端的事務處理;當客戶端沒有啟動一個事務處理,則EJB容器在執行這個方法之前啟動一個新的事務處理.
2、RequiresNew:當客戶端運行一個事務處理并調用EJB的一個方法時,容器管理器做如下操作:
(1) 懸掛客戶端的事務處理;
(2) 開始一個新的事務處理;
(3) 調用方法;
(4) 當方法結束,恢復客戶端的事物處理.
當客戶端沒有啟動一個事務處理,容器管理器在執行這個方法之前啟動一個新的事務處理.
3、Mandatory: 當客戶端運行一個事務處理并調用EJB的一個方法,這個方法在客戶端的事務處理范圍內被執行; 當客戶端沒有啟動一個事務處理,容器管理器將會拋錯(TransactionRequiredException);
4、NotSupported: 當客戶端運行一個事務處理并調用EJB的一個方法,容器管理器在調用方法之前終止客戶端的事務處理,當方法執行完,再恢復客戶端的事務處理; 當客戶端沒有啟動一個事務處理,容器管理器在調用方法時不啟動事務處理.
5、Supports: 當客戶端運行一個事務處理并調用EJB的一個方法,在運行方法時執行客戶端的事務處理; 當客戶端沒有啟動一個事務處理,容器管理器在調用方法時不啟動事務處理.
6、Never: 當客戶端運行一個事務處理并調用EJB的一個方法,容器管理器將拋出一個錯誤(RemoteException); 當客戶端沒有啟動一個事務處理,容器管理器在調用方法時不啟動事務處理.
在jbuilder中,缺省是Required;
第一個ejb可以是 Required,這個ejb調用的那個ejb方法如果想在一個
事務上下文中,我覺得可能采用Mandatory,方式比較好。如果它們不在一個事務上下文中,就會拋錯(TransactionRequiredException),是一個上下文,就沒有問題
幾乎每個做過Web開發的人都問過,到底元素的ID和Name有什么區別阿?為什么有了ID還要有Name呢?而同樣我們也可以得到最classical的答案:ID就像是一個人的身份證號碼,而Name就像是他的名字,ID顯然是唯一的,而Name是可以重復的。
上周我也遇到了ID和Name的問題,在頁面里輸入了一個input type="hidden",只寫了一個ID='SliceInfo',賦值后submit,在后臺用Request.Params["SliceInfo"]卻怎么也去不到值。后來恍然大悟因該用Name來標示,于是在input里加了個Name='SliceInfo',就一切ok了。
第一段里對于ID和Name的解答說的太籠統了,當然那個解釋對于ID來說是完全對的,它就是Client端HTML元素的Identity。而Name其實要復雜的多,因為Name有很多種的用途,所以它并不能完全由ID來代替,從而將其取消掉。
具體用途有:
用途1: 作為可與服務器交互數據的HTML元素的服務器端的標示,比如input、select、textarea、和button等。我們可以在服務器端根據其Name通過Request.Params取得元素提交的值。
用途2: HTML元素Input type='radio'分組,我們知道radio button控件在同一個分組類,check操作是mutex的,同一時間只能選中一個radio,這個分組就是根據相同的Name屬性來實現的。
用途3: 建立頁面中的錨點,我們知道link是獲得一個頁面超級鏈接,如果不用href屬性,而改用Name,如:,我們就獲得了一個頁面錨點。
用途4: 作為對象的Identity,如Applet、Object、Embed等元素。比如在Applet對象實例中,我們將使用其Name來引用該對象。
用途5: 在IMG元素和MAP元素之間關聯的時候,如果要定義IMG的熱點區域,需要使用其屬性usemap,使usemap="#name"(被關聯的MAP元素的Name)。
用途6: 某些特定元素的屬性,如attribute,和param。例如為Object定義參數
顯然這些用途都不是能簡單的使用ID來代替掉的,所以HTML元素的ID和Name的卻別并不是身份證號碼和姓名這樣的區別,它們更本就是不同作用的東西。
當然HTML元素的Name屬性在頁面中也可以起那么一點ID的作用,因為在DHTML對象樹中,我們可以使用document.getElementsByName來獲取一個包含頁面中所有指定Name元素的對象數組。
在這里順便說一下,要是頁面中有n(n>1)個HTML元素的ID都相同了怎么辦?在DHTML對象中怎么引用他們呢?如果我們使用ASPX頁面,這樣的情況是不容易發生的,因為aspnet進程在處理aspx頁面時根本就不允許有ID非唯一,這是頁面會被拋出異常而不能被正常的render。要是不是動態頁面,我們硬要讓ID重復那IE怎么搞呢?
這個時候我們還是可以繼續使用document.getElementById獲取對象,只不過我們只能獲取ID重復的那些對象中在HTML Render時第一個出現的對象。而這時重復的ID會在引用時自動變成一個數組,ID重復的元素按Render的順序依次存在于數組中。
程序題:我想啟動一個線程執行特定的任務,任務的具體執行內容定義在TheRunnable類中(實現了java.lang.Runnable接口):
TheRunnable theRunnable = new TheRunnable();
以下哪個語句可用于啟動theRunnable任務線程:_____
a) theRunnable.run();
b) theRunnable.start();
c) Thread thread = new Thread(theRunnable); thread.run();
d) Thread thread = new Thread(theRunnable); thread.start();
前言
全國青少年信息學(計算機)奧林匹克競賽常常要用到許多經典算法,比如約瑟夫問題、螺旋方陣、漢諾塔、八皇后問題等,而 螺旋方陣問題是其中較為常用的一種。這類問題的算法分析對于計算機圖形學、解析幾何中的相關問題都有一定的啟發性。盡管現有算法已取得了令人振奮的成績, 但依然具有一定的片面性,或者說過于復雜。實際上,這個問題有不同的解決算法,鑒于這個問題具有一定的典型性,本文針對信息學奧林匹克競賽這一問題進行了 全面系統的分析、歸納,從不同的角度對這個問題的算法進行分析并通過程序實現。使讀者對這個問題在算法選擇上有更大的余地,從而避免算法的單一性,同時對 于類似相關問題的解決也有一定的啟發和幫助。
2 問題的描述與分析
關于螺旋方陣的輸出主要是指將一些數據或符號按照一定的順序輸出到計算機的屏幕上或者是輸出到一個指定的文件中去,輸出的幾種常見情況如下圖(為簡單起見,以輸出5階的數字螺旋方陣為例):
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
1 16 15 14 13
2 17 24 25 12
3 18 25 23 11
4 19 20 21 10
5 6 7 8 9
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
21 20 19 18 17
22 7 6 5 16
23 8 1 4 15
24 9 2 3 14
25 10 11 12 13
圖1由外及里順時針;圖2由外及里逆時針;圖3由里及外順時針;圖4由里及外逆時針
在實際應用中,輸出的內容可以不盡相同。在上面的圖1至圖4中,按螺旋順序輸出的數顯然有一定的規律,而實際輸出的順序往往不是按照螺旋順序,通常是將上圖中的數據按行(或按列)輸出,因此這類問題的關鍵在于如何將有規律的數據與實際輸出時的先后順序對應起來。下面采用不同的算法來實現。
3 采用不同算法解決螺旋方陣的輸出
3.1非遞歸算法
3.1.1 “海龜”算法(順時針,由外及里)
參照海龜行走的做法,用一對變量A,B模擬海龜頭的方向,根據屏幕坐標的特點,A、B的取值和“海龜頭”方向有這樣的關系:(0,1)表示向右;(0, -1)表示向左;(-1,0)表示向上;(1,0)表示向下;用另一對變量X,Y模擬海龜位置,“海龜”每前進一步,它的新位置即為X=X+A,Y=Y+B;要海龜向右轉,就改變A、B的值,根據數學知識可以得出具體的變換公式是:C=A;A=B;B=-C。下面用自然語言對算法進行描述:讓海龜先走n步,然后右轉,再走n-1步,再右轉,再走n-1步,再右轉,再走n-2步,再右轉,再走n-2步……如此類推,直到海龜前進的步數為0時停止;而每當“海龜”前進1步,就在它位置上顯示一個數字,那么前進n步即重復執行“X:=X+A,Y:=Y+B”語句n次。但如何讓下兩個循環的重復次數都為n-1呢?解決的方法是:循環n次后,讓n的值減少0.5,然后再轉回執行同樣的循環。擴展到顯示n位數,則須留n列的位置,也就是說,海龜水平方向每次得前進n步,才有足夠的位置顯示大一點的數字方陣,需把Y=Y+B改成Y=Y+n*B就行了。“海龜”算法的優點是簡潔清晰。
3.1.2 “分割”算法(逆時針,由外及里)
設螺旋方陣對應的一般二維數組如下:
a00 a01 a02 a03 a04
a10 a11 a12 a13 a14
a20 a21 a22 a23 a24
a30 a31 a32 a33 a34
a40 a41 a42 a43 a44
圖5
按逆時針方向從外向內,一層層給下標變量賦值,由于階數n的任意性,需考慮以下幾個問題:層數k與階數n的關系式,n由用戶輸入,k根據n來計算;定義變量value,賦值時讓其自增;分析每層矩形四條邊元素的下標變化規律,將方陣元素按逆時針方向分成四個部分:方陣左半邊(三列),方陣下半邊(二行),方陣右半邊(兩列),方陣上半邊(二行)。
具體算法思想:以5階方陣為例,可判斷 k=[(n+1)/2]=3,用循環控制產生的層數,語句為for(k=0,k <(n+1)/2;k++)。
Step1:找出方陣左半邊列規律:列下標正好是層數k的值,行下標在第一列從0變到4,第二列從1變到3,在第三列從2變到2,故推導出n階螺旋方陣左半邊由外到內的列循環結構:for(i=k;i <n-k;i++) mat[i][k]=value++;此循環執行一次,產生一列元素,循環執行的次數由外循環來控制。
Step2:找出方陣下半邊行規律:行下標從4變到3,每層取值為n―k―1;列下標由外到內第一行從1變到4(a40已產生),第二行(a30 、a31已產生)從2變到3,第三行只有一個元素a22,故推導出n階螺旋方陣下半邊行循環結構:for(i=k+1;i <n-k;i++) mat[n-k-1][i]=value++;
Step3:找出方陣右半邊列規律:行下標第一列從3變化到0(a44已產生),第二列從2變到1(a43、a33、a03已產生),可推斷行的初值為n-k-2;列下標沒變化,兩列的下標分別為4、3,故推斷出右半邊的列可由下列循環結構完成:for(i=n-k-2;i >=k;i--) mat[i][n-k-1]=value++;
Step4:找出方陣上半邊行規律:已經產生了的元素不能再重新賦值,而行下標可用層次k來表示,列下標與右半邊行下標變化規律一樣,由此推斷出上半邊的行可由下列循環結構完成:for(i=n-k-2;i >k;i--) mat[k][i]=value++。
當k取一個值時,以上四個循環依序各產生一列或一行元素,由此產生一層元素,當k在變化范圍[0…(n+1)/2]內依次取值時,四個循環輪流執行,一個數字螺旋方陣就這樣生成了。
3.2 遞歸算法
分析圖五容易看出,當由外及里順時針旋轉時,最外層數據輸出后,內層的圖形只不過是層數減少了,即問題的規模變小了,但問題的性質沒有發生變化,新問題和原問題仍然可以采用相同的解法。所以這一問題完全可以采用遞歸的方法來求解。具體的算法描述如下。
Step1:初始化。把需要輸出的數據放入一維數組,設為b[1..n*n]。因為是n階方陣,所以全部元素共有n2個,輸出b[1]到b[n*n]的順序是方陣順時針旋轉的順序。
Step2:把b數組中的每個元素放入到二維數組a[i][j](圖5)中去,如b[1]放入a[0][0]中,b[2]放入a[0][1]中,……,b[6]放入a[1][4]中……,其它元素依次放入。
Step3:按行輸出數組元素a[i][j]即可。
上述算法中,難點在于如何將b數組放入到a[i][j]數組對應的分量中去。為此,對step2進行求精并使用遞歸來解決。具體做法:將數組a初始化為0。設置變量direction作為方向標志。當direction為1、2、3、4時,分別表示向右、向下、向左、向上。并編寫如下的遞歸子程序walk(x,y,direction,k)。其中參數x,y表示數組的下標。k是計數器。當 k>n*n 為遞歸出口。
case direction of
{right } 1: if到右邊界then 向下拐 else 向右輸出;
{down} 2: if到下邊界 then 向左拐 else 向下輸出;
{left} 3: if到左邊界 then 向上拐 else 向左輸出;
{up} 4: if 到上邊界 then 向右拐 else 向上輸出。
end;{end case}
3.3 算法實現
限于篇幅,本文僅給出遞歸算法的主要程序段(pascal語言)
procedure walk(x,y,direction,k:integer);
begin
if k>n*n then 按行輸出a數組;
a[x,y]:=b[k];
case direction of
{right}1: if (y=n) or (a[x,y+1]<>0) then walk(x+1,y,2,k+1) else walk(x,y+1,1,k+1);
{down}2: if (x=n) or (a[x+1,y]<>0) then walk(x,y-1,3,k+1) else walk(x+1,y,2,k+1);
{left} 3: if (y=1) or (a[x,y-1]<>0) then walk(x-1,y,4,k+1) else walk(x,y-1,3,k+1);
{up} 4: if (x=1) or (a[x-1,y]<>0) then walk(x,y+1,1,k+1) else walk(x-1,y,4,k+1)
end;
begin{main}
fillchar(a,sizeof(a),0);
writeln('please input a integer for n:');
readln(n);
walk(1,1,1,1);
end.{end main}
4 結束語
關于螺旋方陣的輸出算法主要有上述幾種,其他幾種方陣的輸出,可以仿照上述的算法分析加以實現。相對而言,遞 歸算法較為簡潔,但是時間復雜度要高一些,對于輸出高階螺旋方陣時,時間很長。另外在空間復雜度方面,采用數組這種數據結構,顯然有一定的局限性,如果使 用鏈表來存儲,將會盡可能地避免空間不足的現象。另外,上述問題也可以使用一個模板式的子程序來完成,這時要求輸入的參數要包括:從外還是從里螺旋、順時 針還是逆時針,起點坐標等參數,對于從里向外螺旋時,還要考慮螺旋方陣的階數是奇數還是偶數,分別給予不同的處理。
本篇文章來源于 義烏信息技術教研網 原文鏈接:http://www.ywhs.net/itedu/html/aosaifudao/mingshifudao/20071125/47.html
Java最初是在瀏覽器和客戶端機器中粉墨登場的。當時,很多人質疑它是否適合做服務器端的開發。現在,隨著對Java2平臺企業版(J2EE)第三方支持的增多,Java被廣泛接納為開發企業級服務器端解決方案的首選平臺之一。
J2EE平臺由一整套服務(Services)、應用程序接口(APIs)和協議構成,它對開發基于Web的多層應用提供了功能支持。
在本文中我將解釋支撐J2EE的13種核心技術:JDBC, JNDI, EJBs, RMI, JSP, Java servlets, XML, JMS, Java IDL, JTS, JTA, JavaMail 和 JAF,同時還將描述在何時、何處需要使用這些技術。當然,我還要介紹這些不同的技術之間是如何交互的。
此外,為了讓您更好地感受J2EE的真實應用,我將在WebLogic應用服務器,來自BEA Systems公司的一種廣為應用的產品環境下來介紹這些技術。不論對于WebLogic應用服務器和J2EE的新手,還是那些想了解J2EE能帶來什么好處的項目管理者和系統分析員,相信本文一定很有參考價值。
宏觀印象: 分布式結構和J2EE
過去,二層化應用 -- 通常被稱為client/server應用 -- 是大家談論的最多的。在很多情況下,服務器提供的惟一服務就是數據庫服務。在這種解決方案中,客戶端程序負責數據訪問、實現業務邏輯、用合適的樣式顯示結果、彈出預設的用戶界面、接受用戶輸入等。client/server結構通常在第一次部署的時候比較容易,但難于升級或改進,而且經常基于某種專有的協議,通常是某種數據庫協議。它使得重用業務邏輯和界面邏輯非常困難。更重要的是,在Web時代,二層化應用通常不能體現出很好的伸縮性,因而很難適應Internet的要求。
Sun設計J2EE的部分起因就是想解決二層化結構的缺陷。于是,J2EE定義了一套標準來簡化N層企業級應用的開發。它定義了一套標準化的組件,并為這些組件提供了完整的服務。J2EE還自動為應用程序處理了很多實現細節,如安全、多線程等。
用J2EE開發N層應用包括將二層化結構中的不同層面切分成許多層。一個N層化應用A能夠為以下的每種服務提供一個分開的層:
顯示:在一個典型的Web應用中,客戶端機器上運行的瀏覽器負責實現用戶界面。
動態生成顯示: 盡管瀏覽器可以完成某些動態內容顯示,但為了兼容不同的瀏覽器,這些動態生成工作應該放在Web服務器端進行,使用JSP、Servlets,或者XML(可擴展標記語言)和(可擴展樣式表語言)。
業務邏輯:業務邏輯適合用Session EJBs(后面將介紹)來實現。
數據訪問:數據訪問適合用Entity EJBs(后面將介紹)和JDBC來實現。
后臺系統集成: 同后臺系統的集成可能需要用到許多不同的技術,至于何種最佳需要根據后臺系統的特征而定。
您可能開始詫異:為什么有這么多的層?事實上,多層方式可以使企業級應用具有很強的伸縮性,它允許每層專注于特定的角色。例如,讓Web服務器負責提供頁面,應用服務器處理應用邏輯,而數據庫服務器提供數據庫服務。
由于J2EE建立在Java2平臺標準版(J2SE)的基礎上,所以具備了J2SE的所有優點和功能。包括“編寫一次,到處可用”的可移植性、通過JDBC訪問數據庫、同原有企業資源進行交互的CORBA技術,以及一個經過驗證的安全模型。在這些基礎上,J2EE又增加了對EJB(企業級Java組件)、Java servlets、Java服務器頁面(JSPs)和XML技術的支持。
分布式結構與WebLogic應用服務器
J2EE提供了一個框架--一套標準API--用于開發分布式結構的應用,這個框架的實際實現留給了第三方廠商。部分廠商只是專注于整個J2EE架構中的的特定組件,例如Apache的Tomcat提供了對JSP和servlets的支持,BEA系統公司則通過其WebLogic應用服務器產品為整個J2EE規范提供了一個較為完整的實現。
WebLogic服務器已使建立和部署伸縮性較好的分布式應用的過程大為簡化。WebLogic和J2EE代你處理了大量常規的編程任務,包括提供事務服務、安全領域、可靠的消息、名字和目錄服務、數據庫訪問和連接池、線程池、負載平衡和容錯處理等。
通過以一種標準、易用的方式提供這些公共服務,象WebLogic服務器這樣的產品造就了具有更好伸縮性和可維護性的應用系統,使其為大量的用戶提供了增長的可用性。
J2EE技術
在接下來的部分里,我們將描述構成J2EE的各種技術,并且了解WebLogic服務器是如何在一個分布式應用中對它們進行支持的。最常用的J2EE技術應該是JDBC、JNDI、EJB、JSP和servlets,對這些我們將作更仔細的考察。
Java Database Connectivity (JDBC)
JDBC API以一種統一的方式來對各種各樣的數據庫進行存取。和ODBC一樣,JDBC為開發人員隱藏了不同數據庫的不同特性。另外,由于JDBC建立在Java的基礎上,因此還提供了數據庫存取的平臺獨立性。
JDBC定義了4種不同的驅動程序,現分述如下:
類型 1: JDBC-ODBC Bridge
在JDBC出現的初期,JDBC-ODBC橋顯然是非常有實用意義的,通過JDBC-ODBC橋,開發人員可以使用JDBC來存取ODBC數據源。不足的是,他需要在客戶端安裝ODBC驅動程序,換句話說,必須安裝Microsoft Windows的某個版本。使用這一類型你需要犧牲JDBC的平臺獨立性。另外,ODBC驅動程序還需要具有客戶端的控制權限。
類型 2: JDBC-native driver bridge
JDBC本地驅動程序橋提供了一種JDBC接口,它建立在本地數據庫驅動程序的頂層,而不需要使用ODBC。 JDBC驅動程序將對數據庫的API從標準的JDBC調用轉換為本地調用。使用此類型需要犧牲JDBC的平臺獨立性,還要求在客戶端安裝一些本地代碼。
類型 3: JDBC-network bridge
JDBC網絡橋驅動程序不再需要客戶端數據庫驅動程序。它使用網絡上的中間服務器來存取數據庫。這種應用使得以下技術的實現有了可能,這些技術包括負載均衡、連接緩沖池和數據緩存等。由于第3種類型往往只需要相對更少的下載時間,具有平臺獨立性,而且不需要在客戶端安裝并取得控制權,所以很適合于Internet上的應用。
類型 4: Pure Java driver
第4種類型通過使用一個純Java數據庫驅動程序來執行數據庫的直接訪問。此類型實際上在客戶端實現了2層結構。要在N-層結構中應用,一個更好的做法是編寫一個EJB,讓它包含存取代碼并提供一個對客戶端具有數據庫獨立性的服務。
WebLogic服務器為一些通常的數據庫提供了JDBC驅動程序,包括Oracle, Sybase, Microsoft SQL Server以及Informix。它也帶有一種JDBC驅動程序用于Cloudscape,這是一種純Java的DBMS,WebLogic服務器中帶有該數據庫的評估版本。
以下讓我們看一個實例。
JDBC實例
在這個例子中我們假定你已經在Cloudscape中建立了一個PhoneBook數據庫,并且包含一個表,名為 CONTACT_TABLE ,它帶有2個字段:NAME 和 PHONE。 開始的時候先裝載Cloudscape JDBC driver,并請求 driver manager得到一個對PhoneBook Cloudscape數據庫的連接。通過這一連接,我們可以構造一個 Statement 對象并用它來執行一個簡單的SQL查詢。最后,用循環來遍歷結果集的所有數據,并用標準輸出將NAME和PHONE字段的內容進行輸出。
創建新表:
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根據已有的表創建新表:
A:create table tab_new like tab_old
B:create table tab_new as select col1,col2… from tab_old definition only