国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

數(shù)據(jù)庫中用一個(gè)值來保存多種情況:二進(jìn)制和按位異或

luckyyulin / 3535人閱讀

摘要:通過這個(gè)方法,我們可以非常順利的在一個(gè)數(shù)據(jù)表中用一個(gè)值保存多種情況。了解了這個(gè)原理之后,我們只需要在數(shù)據(jù)庫中保存二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值,在查詢時(shí),用對(duì)比值二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值去按位異或一下,即可得到我們想要的結(jié)果。

例如,某個(gè)房間可從[燈,床,桌,椅,杯子,飲水機(jī)……]這些器具中挑選,從而組成這個(gè)房間的裝潢。我們可能會(huì)設(shè)計(jì)一個(gè)房間表,再設(shè)計(jì)一個(gè)器具表,再設(shè)計(jì)一個(gè)關(guān)系表,通過這個(gè)關(guān)系表來保存它們之間的對(duì)應(yīng)關(guān)系。但是這樣的效率明顯是比較差的,需要同時(shí)查詢?nèi)龔埍聿拍芡瓿伞?/p>

為了不適用關(guān)系表,我們還可以在房間表中設(shè)計(jì)一個(gè)字段,通過一個(gè)有規(guī)律的字符串來保存器具表的器具ID,例如:

1,2,3,7

下面,我們提供一種通過一個(gè)值來計(jì)算即可獲得這一器具組合的結(jié)果,方法如下:

array(
  "1" => "燈"
  "2" => "床",
  "4" => "桌",
  "8" => "椅子",
  "16" => "飲水機(jī)",
  ……
);

如果我們將5保存到數(shù)據(jù)庫中,我們可以立馬知道,這個(gè)房間有“燈”和“桌”,而如果保存的是23,則一定有“燈”“床”“桌”和“飲水機(jī)”。

給每一個(gè)器具一個(gè)給定的值,這個(gè)值一定是2的n次方(n>=0),這樣就可以保證相加之后的值可以反解。這個(gè)情況的核心原理在于,給定任何數(shù)值的前面數(shù)值相加和,一定小于當(dāng)前數(shù)值。如何進(jìn)行反解呢?

例如我們拿到一個(gè)值為N,那么我們可以首先找到最大的2^n,確定2^n是一定有的,如果沒有2^n,就不可能相加得到N。

接下來我們獲得M = N - 2^n,找到最大的2^m,再進(jìn)行M - 2^m,如此推論下去,直到減完為止。

那么怎獲得最大的2^n呢?

$n = (int)log(N,2);

log函數(shù)在PHP4+之后內(nèi)置,用于取對(duì)數(shù),返回值為float類型,但我們僅需要整數(shù)部分,因此前面加(int)。

例如N=22,那么$n=4,再去計(jì)算2^4,就是16。

通過這個(gè)方法,我們可以非常順利的在一個(gè)數(shù)據(jù)表中用一個(gè)值保存多種情況。但是,這也有一定的適用范圍,比如這些情況最好是固定不變的,2n值不能太大等等。通過這種方法可以用該值進(jìn)行權(quán)重設(shè)計(jì),進(jìn)行排序,但是不能用于條件檢索,比如你想檢索數(shù)據(jù)庫中包含“床”的房間,你就不好進(jìn)行檢索,因?yàn)榇蟛糠址块g的該值可能都大于2.所以,在使用這種方法時(shí),應(yīng)該根據(jù)實(shí)際需要進(jìn)行考慮。

更新:

在數(shù)據(jù)庫中,我們可以使用一種序列化的類二進(jìn)制字符串來保存多個(gè)值,當(dāng)這個(gè)二進(jìn)制值是以01組成時(shí),實(shí)際上就可以換算成為一個(gè)十進(jìn)制數(shù),從而也就實(shí)現(xiàn)了一個(gè)十進(jìn)制值保存多種情況的目的。

下面我們來做一個(gè)演示。

例如我們?cè)谟喥毕到y(tǒng)中,規(guī)定某一個(gè)活動(dòng)每天分為6個(gè)場(chǎng)次,每個(gè)場(chǎng)次2個(gè)小時(shí),因此實(shí)際上就把一天的12個(gè)小時(shí)分為了6份,分別是9:00-11:00,11:00-13:00,13:00-15:00,15:00-17:00,17:00-19:00:19:00-21:00,我們用“xxxxxx”(x取0或1)來表示,現(xiàn)在,我們要記錄這些場(chǎng)次是否全部被定完了,用1表示全部被訂完,所以“010110”就表示11:00-13:00,15:00-17:00,17:00-19:00這三個(gè)場(chǎng)次已經(jīng)被訂完了,不能再對(duì)外售票。

我們?cè)跀?shù)據(jù)庫中怎么保存呢?

php提供了將二進(jìn)制轉(zhuǎn)換為十進(jìn)制的函數(shù)bindec(),我們先將二進(jìn)制值轉(zhuǎn)換為十進(jìn)制值后,再保存到數(shù)據(jù)庫中。而當(dāng)我們要使用時(shí),從數(shù)據(jù)庫中取出十進(jìn)制值,再使用decbin()將值轉(zhuǎn)換為二進(jìn)制值,當(dāng)然,我們要補(bǔ)全最后得到的二進(jìn)制值的位數(shù),也就是前面加0,然后再進(jìn)行字符串?dāng)?shù)組處理,進(jìn)行對(duì)比。

在編程世界中,還有一個(gè)比較好玩的算法,叫“按位異或”。按位,就是以二進(jìn)制的形式進(jìn)行計(jì)算,“按位異或”就是兩個(gè)位的值不同時(shí)返回1,否則返回0。通過這個(gè)運(yùn)算,我們可以得到看上去非常復(fù)雜的結(jié)果。在php中,運(yùn)算為“^”。下面我們來進(jìn)行一下演算。

001011 ^ 011010 = 010001 (1式,注意,開頭的0會(huì)被忽略,因此不要把開頭的0也算進(jìn)來)

提按位異或有什么意義呢?因?yàn)槎M(jìn)制值可以和十進(jìn)制值進(jìn)行轉(zhuǎn)換,因此我們將二進(jìn)制值轉(zhuǎn)換為十進(jìn)制值進(jìn)行按位異或之后,得到的值也是十進(jìn)制的,我們只有將這些十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制字串后,才能發(fā)現(xiàn)規(guī)律,但是如果我們直接用十進(jìn)制進(jìn)行計(jì)算,卻能快速得到結(jié)果。

下面我們就來演算一次,我們拿(1式)來看。如果將二進(jìn)制數(shù)轉(zhuǎn)換為十進(jìn)制,我們就能得到

11 ^ 26 = 17

那事實(shí)的結(jié)果是不是這樣呢?你可以在你的php程序中寫上:


是的,結(jié)果就是這樣。可是,這個(gè)復(fù)雜的運(yùn)算有什么用呢?它可以用于比較。比如我們的數(shù)據(jù)庫中存放了11,轉(zhuǎn)換為二進(jìn)制就是“001011”,也就是表示這一天的場(chǎng)次中,對(duì)應(yīng)的那三個(gè)時(shí)段已經(jīng)滿票了。但是如果我們現(xiàn)在正好要進(jìn)行對(duì)比,看看這一天中17:00-19:00這個(gè)時(shí)段是否滿票,我們?cè)趺茨軠?zhǔn)確知道11這個(gè)值轉(zhuǎn)換為001011后,第5個(gè)位上的值是否為1呢?

我們只需要用這種思路來解決即可:

xxxxxx ^ 000010 = ?

其中xxxxxx是我們要對(duì)比的值,比如當(dāng)它等于11時(shí),也就是001011時(shí),等式的右邊會(huì)得到001001(9)。我們?cè)賮砜戳硪粋€(gè)算式:

xxxxxx ^ 000000 = ?

等式右邊會(huì)得到本身。

如果我們?cè)儆?01001(9)去按位異或000010,則會(huì)得到001011(11)。

我們得到的結(jié)論就是,凡是用xxxxx去按位異或yyyyyy(其中只有一個(gè)y為1,其他全為0),得到的結(jié)果比自身小的,則對(duì)應(yīng)位置上的值為1,得到的結(jié)果比自身大的,對(duì)應(yīng)的位置上為0。通過這種方法,也就找到了哪個(gè)時(shí)間段是被訂滿票的。

為什么大于自身的,對(duì)應(yīng)的位置上就一定為0呢?因?yàn)?^1=1,而二進(jìn)制數(shù)是01構(gòu)成的,也就是說0和1碰上0時(shí),都不會(huì)變化,而只有0碰上1時(shí)才會(huì)變化。說白了,用任何一個(gè)二進(jìn)制數(shù)去按位異或000100,結(jié)果發(fā)生的情況就兩種,一種是第四個(gè)位置上的值由1變?yōu)?(結(jié)果值相對(duì)于本身值而言),這種情況下該值變小,一種是第四個(gè)位置上的值由0變?yōu)?,這種情況下該值變大。了解了這個(gè)原理之后,我們只需要在數(shù)據(jù)庫中保存二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值,在查詢時(shí),用對(duì)比值(二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值)去按位異或一下,即可得到我們想要的結(jié)果。

我們創(chuàng)建如下表結(jié)構(gòu),sale_over在實(shí)際存儲(chǔ)時(shí),我們轉(zhuǎn)換為十進(jìn)制整數(shù)進(jìn)行存儲(chǔ),這里方便演示用二進(jìn)制表示。每次在用戶下訂單時(shí)對(duì)票數(shù)進(jìn)行檢查,如果該時(shí)段已經(jīng)有20張票被訂出,就在下表中更新一條記錄,把對(duì)應(yīng)的時(shí)段改為1.

tablename = objectorder

id object_id day sale_over
1 5 2015-08-23 011000
2 8 2015-08-24 100101
3 5 2015-08-25 010001

例如:

SELECT COUNT(id) FROM object_order WHERE object_id=8 AND day="2015-08-20" AND (hours ^ 2)

這樣就可以判斷出8月20號(hào)這天17:00-19:00這個(gè)時(shí)間段是否被訂滿(如果返回1,則表示被訂滿了)。

如果我們不滿意用大小比較來進(jìn)行判斷,我們還可以深入發(fā)現(xiàn),按位異或結(jié)果與原值之間的差值,正好是用來異或的值,也就是滿足下面的等式:

|m ^ n - m| = n (n為yyyyyy,只有一個(gè)y為1,其他為0)

|x|是指絕對(duì)值,當(dāng)不取覺得值,得到的為負(fù)數(shù)時(shí),說明結(jié)果變小了,那么原值對(duì)應(yīng)的位置上也就是1,而如果得到的為正數(shù),說明結(jié)果變大,對(duì)應(yīng)的位置上就為0。所以,上述sql,我們還可以這樣去改:

**SELECT COUNT(id) FROM object_order WHERE object_id=8 AND day="2015-08-20" AND (hours ^ 2 + 2)=hours;**

如果查到了結(jié)果,說明8這個(gè)活動(dòng)8月20號(hào)這天17:00-19:00這個(gè)時(shí)間段被訂滿。

這種魔術(shù)般的使用方法,你是否思考過呢?

再議

實(shí)際上,一個(gè)二進(jìn)制數(shù),我們將它轉(zhuǎn)換為十進(jìn)制時(shí),將它的各個(gè)位置值(從右往左,以0為開始)作為次數(shù)求2的次冪,再乘以該位置上的數(shù),再相加,即得到該二進(jìn)制數(shù)對(duì)應(yīng)的十進(jìn)制數(shù),例如:

10100 = 0(2^0) + 0(2^1) + 1(2^3) + 0(2^4) + 1*(2^5) = 8 + 32 = 40

這樣去觀察,就發(fā)現(xiàn)實(shí)際上8和32,就是我們第一次接觸這種算法時(shí),將它們作為一個(gè)數(shù)組的索引值,進(jìn)行物品的索引進(jìn)行計(jì)算。

接下來,我們要更換場(chǎng)景,每個(gè)時(shí)段僅可以被一個(gè)人預(yù)訂,用戶每一次下訂單完成之后,形成一條記錄,這些記錄以上述形式存儲(chǔ),得到如下訂單數(shù)據(jù)表:

tablename = userorder

id user_id object_id day hours
1 2 5 2015-08-23 011000
2 3 8 2015-08-24 100000
3 2 5 2015-08-24 000001

類似這樣的訂單記錄,hours字段中每個(gè)位置上的1最多出現(xiàn)1次,怎么樣確定某一天的所有票都已經(jīng)定出去了呢?

其實(shí)這是最簡(jiǎn)單的,就是對(duì)該字段進(jìn)行求和,例如:

SELECT SUM(hours) FROM user_order WHERE object_id=8 AND day="2015-08-20";

如果最終得到的值為111111,也就是十進(jìn)制的63,則說明該天各個(gè)時(shí)段已訂滿,不能再進(jìn)行預(yù)訂。

最后一種情況則是對(duì)上面兩張場(chǎng)景的結(jié)合,也就是每個(gè)時(shí)段最多可以被預(yù)訂20張票,數(shù)據(jù)庫中記錄的是單個(gè)用戶的訂單。

當(dāng)然,遇到這種情況,其實(shí)我們可以準(zhǔn)備兩張表,一張是用戶的訂單表:

tablename = userorder

id user_id object_id day hours
1 2 5 2015-08-23 011000
2 3 8 2015-08-24 100000
3 2 5 2015-08-24 000001

(第一條記錄表示用戶2在2015-08-23這天預(yù)訂了5這個(gè)活動(dòng)的11點(diǎn)13點(diǎn)這兩個(gè)時(shí)段的票)

一張用來在每次用戶訂單完成時(shí),對(duì)該時(shí)段進(jìn)行判斷,如果這個(gè)時(shí)段已經(jīng)賣出20張,就改為1,進(jìn)行更新操作的場(chǎng)次預(yù)訂情況表:

tablename = objectorder

id object_id day sale_over
1 5 2015-08-23 011000
2 8 2015-08-24 100101
3 5 2015-08-25 010001

但是這樣的話,我們通過該表,僅能判斷是否賣完,而不知道已經(jīng)賣了多少張。為了解決這個(gè)問題,我們夸張的做法是,直接在這個(gè)表的基礎(chǔ)上進(jìn)行擴(kuò)展,增加20個(gè)字段,每個(gè)字段對(duì)應(yīng)一個(gè)時(shí)段,用來記錄所賣出的票數(shù),但是這樣實(shí)在太蠢了。由于二進(jìn)制方式,無法在每個(gè)位置上表示實(shí)際的值,例如在第2個(gè)位置上用3來表示賣出3張,這是我們無法做到的,所以,我們可以通過前面一張用戶下的訂單列表來進(jìn)行計(jì)算,從而找出某個(gè)位置上是否已經(jīng)存在20個(gè)1.

實(shí)際上,我們現(xiàn)在要解決的,就是查出每個(gè)時(shí)段已經(jīng)訂出了多少張票。

我們可以用

SELECT COUNT(id) FROM user_order WHERE object_id=8 AND day="2015-08-20" AND (hours ^ 2 + 2)=hours;

這種方法就可以查出來某個(gè)時(shí)段的被訂數(shù)量,如果返回值等于20,則說明該時(shí)段已經(jīng)被定完了。但是,我們?nèi)绾螐乃械挠涗浿校页瞿切┨斓南槐蝗慷ü饽兀恳驗(yàn)槲覀儾淮蛩闶褂胦bjectorder表來記錄,而是想直接通過userorder進(jìn)行查詢,所以我們不僅要判斷某個(gè)位置上的為1的記錄數(shù)是否為20,而且要判斷所有的位置。

最笨的方法就是連續(xù)判斷6次,對(duì)每個(gè)位置都進(jìn)行統(tǒng)計(jì),最終進(jìn)行判斷。但是這明顯不符合我們的要求。

實(shí)際上,我們?nèi)匀皇褂们蠛图纯赏瓿桑覀冊(cè)谇懊孢M(jìn)行求和時(shí),只需要用111111進(jìn)行對(duì)比,也就是十進(jìn)制的63進(jìn)行對(duì)比,而這次,我們用20個(gè)111111進(jìn)行對(duì)比,也就是63*20 = 1260進(jìn)行對(duì)比即可。

SELECT SUM(hours) FROM user_order WHERE object_id=8 AND day="2015-08-20";

如果得到的返回值等于1260,說明這一天的所有場(chǎng)次已經(jīng)完全訂出去了。

用這種方法處理數(shù)據(jù)庫中保存有規(guī)律的多種情況保存,就變得輕松有趣了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/17483.html

相關(guān)文章

  • 數(shù)據(jù)庫中用一個(gè)值來保存多種情況進(jìn)制和按異或

    摘要:通過這個(gè)方法,我們可以非常順利的在一個(gè)數(shù)據(jù)表中用一個(gè)值保存多種情況。了解了這個(gè)原理之后,我們只需要在數(shù)據(jù)庫中保存二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值,在查詢時(shí),用對(duì)比值二進(jìn)制轉(zhuǎn)換而來的十進(jìn)制值去按位異或一下,即可得到我們想要的結(jié)果。 例如,某個(gè)房間可從[燈,床,桌,椅,杯子,飲水機(jī)……]這些器具中挑選,從而組成這個(gè)房間的裝潢。我們可能會(huì)設(shè)計(jì)一個(gè)房間表,再設(shè)計(jì)一個(gè)器具表,再設(shè)計(jì)一個(gè)關(guān)系表,通過這個(gè)關(guān)...

    qieangel2013 評(píng)論0 收藏0
  • 淺談JavaScript位操作符

    摘要:有符號(hào)的右移操作符由兩個(gè)大于符號(hào)表示這個(gè)操作符的含義就是將數(shù)值的位向右移指定的位數(shù)同時(shí)保留符號(hào)位的值正負(fù)號(hào)標(biāo)記有符號(hào)的右移操作符與左移操作符剛好相反比如向右移動(dòng)位就是同樣的在移位的過程中也會(huì)出 位操作符的基本概念 因?yàn)镋CMAscript中所有數(shù)值都是以IEEE-75464格式存儲(chǔ),所以才會(huì)誕生了位操作符的概念. 位操作符作用于最基本的層次上,因?yàn)閿?shù)值按位存儲(chǔ),所以位操作符的作用也就是...

    fasss 評(píng)論0 收藏0
  • 【STM32】位操作、按位與、按位或、按異或、取反、左移、右移等基礎(chǔ) C 語言知識(shí)補(bǔ)充

    摘要:總結(jié)對(duì)于原二進(jìn)制數(shù)來說,是不變,是反轉(zhuǎn)。的位數(shù)對(duì)應(yīng)原二進(jìn)制數(shù)的位數(shù),對(duì)各位進(jìn)行屏蔽,全部置。左移左移與右移比較類似,是將目標(biāo)二進(jìn)制數(shù)字向左右移動(dòng)相應(yīng)的位數(shù)。語言中的邏輯運(yùn)算符按位與,按位或,按位異或,取反,左右移位不完全手冊(cè)立創(chuàng)開源 ...

    waruqi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<