部分真题整理2
1、聲明一個指向含有10個元素的數組的指針,其中每個元素是一個函數指針,該函數的返回值是int,參數是int*,正確的是(C)
(int *p[10])(int*) int [10]*p(int *) int (*(*p)[10])(int *) int ((int *)[10])*p以上選項都不正確
解析:
int (*(*func)[5])(int *p);
func被一個圓括號包含,左邊又有一個*,那么func是一個指針,跳出括號,右邊是一個[]運算符號,說明func是一個指向數組的指針,現在往左看,左邊有一個*號,說明這個數組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數組的元素是指向函數的指針??偨Y一下,就是:func是一個指向數組的指針,這個數組的元素是函數指針,這些指針指向具有int*形參,返回值為int類型的函數。
詳見:http://blog.csdn.net/u011385799/article/details/47783555
2、 一個進程從執行狀態轉換到阻塞狀態的可能原因是本進程(BD)。
時間片完
需要等待其他進程的執行結果
執行了V操作
執行了P操作
解析:
運行態:進程占用CPU,并在CPU上運行;
就緒態:進程已經具備運行條件,但是CPU還沒有分配過來;
阻塞態:進程因等待某件事發生而暫時不能運行; 進程在一生中,都處于上述3中狀態之一。
運行---》就緒: 時間片用完。
就緒---》運行:運行的進程的時間片用完,調度就轉到就緒隊列中選擇合適的進程分配CPU
運行---》阻塞:發生了I/O請求或等待某件事的發生
阻塞---》就緒:進程所等待的事件發生,就進入就緒隊列
P操作是阻塞作用
V操作是喚醒作用
13
15
26
(1)b=a*2,c=a+11,a=c,a=b a=4
(2)b=a*2,c=a+11,a=b,a=c a=13
(3)b=a*2,a=b,c=a+11,a=c a=15
(4)c=a+11,a=c,b=a*2,a=b a=26
4、以下程序段的輸出結果是(A)
char s[]="\\123456\123456\t"; printf("%d\n",strlen(s));12
13
16
以上都不對
解析:
char s[] = "//123456/123456/t";
這樣strlen(s)輸出17.
char s[] = "\\123456\123456\t";
這樣strlen(s)輸出12.
計算字符串長度時關鍵是要注意辨認轉義字符;
含轉義字符的有:
\\ 表示字符 \
\123表示字符 {
\t 表示制表符
這些都是一個字符。
5、如下程序
#include <iostream> using namespace std;class A { public: A() { printf("A"); } };int main() { A *p1 = new A; A *p2 = (A *)malloc(sizeof(A));return 0; }該程序運行結果為(A)
A
AA
崩潰
不可預測
解析:
1 A *p1 = new A;
上面這條語句會創建一個A對象,輸出一個A;
1 A *p2 = (A *)malloc(sizeof(A));
sozeof(A)為1,這條語句創建一個大小為1的A的指針數組,但是沒有創建任何A對象,因此不輸出A
這題主要是考的new和malloc的區別,new會分配內存,并調用類的構造函數創建對象,而malloc只是分配內存,不調用類的構造函數創建對象,這個程序應該用delete p1;顯示釋放掉p1所指的堆上的內存,這樣才會調用類的析構函數,否則不會調用。
6、設有以下宏定義:
#define N 3 #define Y(n)((N+1)*n)則執行語句:z=2*(N+Y(5+1));后,z的值為:(C)
38
42
48
54
解析:
#define N 3
#define Y(n)((N+1)*n)//【注意此處n沒有加括號】,所以后面的n并不是(5+1)
z=2*(N+Y(5+1)) =2*(N+(N+1)*5+1)=2*(3+4*5+1)=48
7、 以下描述正確的是?(C)
虛函數是可以內聯的,可以減少函數調用的開銷提高效率
類里面可以同時存在函數名和參數都一樣的虛函數和靜態函數
父類的析構函數是非虛的,但是子類的析構函數是虛的,delete子類對象指針會調用父類的析構函數
以上都不對
解析:
delete子類對象是一定會調用父類的析構函數的先調用子類的析構函數然后調用父類的析構函數;如果要調用父類指向子類的對象,此時才需要父類的析構函數是虛的。
8、下列運算符中,在C++語言中不能重載的是:(C)
*
>=
::
delete
解析:
在C++中,sizeof運算符,.成員運算符,.*成員指針運算符,::作用域解析運算符以及?:條件運算符不能被重載
9、說明一下++p 與 p++ 的區別。(B)
沒有區別
++p更好一些
p++更好一些
和編譯器有關
解析:
假設這樣的一個例子:
int p = -1; int y = 0; y = p++ + ++P;先分析一下它的匯編代碼(沒有優化):
subl $40, %esp ; 分配40字節 movl $1, -16(%ebp) ; 存儲 p movl $0, -12(%ebp) ; 存儲 y movl -16(%ebp), %eax ; 這3步執行 p++ leal 1(%eax), %edx movl %edx, -16(%ebp) addl $1, -16(%ebp) ; 這2步執行 ++p movl -16(%ebp), %edx addl %eax, %edx ; 相加操作 movl %edx, -12(%ebp) ; 結果寫回 y 可以看出p++需要3步,++p需要2步,而且修改p的值是不一樣的,看出++p的效率比p++的高。
前++返回對象的引用,效率較高,故選擇++p
10、下面有關final, finally, finalize的區別描述錯誤的是?(B)
如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承
如果一個方法被聲明為final,可以被覆蓋
finally在異常處理時提供 finally 塊來執行任何清除操作。
Java使用 finalize() 方法在垃圾收集器象從內存中清除出去之前做必要的清理工作
解析:
final關鍵字可用于修飾類、變量和方法。final修飾的類不能被繼承,final修飾的方法不能被重寫,final修飾的變量不可被修改,一旦獲得初始值,該變量就不能被重新賦值。
11、 以下選項中函數形參不是指針的是?(C)
fun( int ﹡a ){…}
fun( int a [ 10 ] ) {…}
fun( int &p ) {…}
fun( int p[ ]) {…}
解析:
B選項和D選項是將數組作為函數參數;A選項是將指針作為函數參數;
C. 這個& 是引用,不是取地址.
12、下面程序應該輸出多少?(A)
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" }; char **cp[] = { c+3, c+2, c+1, c }; char ***cpp = cp; int main(void) { printf("%s", **++cpp); printf("%s", *--*++cpp+3); printf("%s", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); return 0; }POINTERSTEW
FERSTEPOINW
NEWPOINTW
POINTFIREST
解析:
這個主要是執行順序的問題,我加了一下括號:
printf("%s\n", **(++cpp));
printf("%s\n", (*(--(*(++cpp)))) + 3);
printf("%s\n", *(cpp[-2]) + 3);
printf("%s\n", cpp[-1][-1] + 1);
其中考了指針應用,隱含中也考了運算符優先級的問題(*--*++cpp+3)
c是一個指針數組,每個數組單元都是一個指針,指向一個字符創。
即c[0]="ENTER"......c[3]="FIRST"
由于[]與*運算本質幾乎是一致的,以下用[]替換*更容易理解。
c[i]=*(c+i)
c和c+i都是char*[]類型,它可以退化成char**類型,它正好是一個char**數組
cp[0]=c+3 .....cp[3]=c
引用后cp[0][0]=*(c+3)=c[3]="FIRST"
cp是char**[]類型,它可以退化成char***類型,正好與cpp類型一致。
1>++ccp的值是cp+1 *++p=*(cp+1)=cp[1] **++p=*(cp[1])=c[2]="POINT"
2>運算符優先級決定運算先后關系
++ccp的值是cp+2 *++p=*(cp+2)=cp[2]=c+1 --*++p=c *--*++p=*(c+0)=c[0]="ENTER"再+3字符串指向"ER"
3>cpp的值為cp+2 cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3再引用*(c+3)=c[3]="FIRST"字符串指到"ST"
4>cpp的值沒變,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2再[-1]得*(c+2-1)=c[1]="NEW",+1字符創指針指到"EW"
翻來覆去,記得這個換算關系式即可,c[i]=*(c+i)。
13、 有如下程序段:
void GetMemeory(char* p) { p = (char*) malloc (100); } void test() { char *str=NULL; GetMemory(str); strcpy(str,”Thunder”); strcat(str+2, “Downloader”);//*(str+2)=u;把Downloader連接到str+2的串尾后 printf(str); }請問運行Test函數結果是:(D)
Thunder Downloader
under Downloader
Thunderownloader
程序崩潰
解析:
在函數中給指針分配空間,實際上是給指針的臨時變量分配空間,函數結束后,這個臨時變量也消亡,而str仍然為NULL,沒有為其分配空間,此時strcpy()是肯定會出錯的。
若改為void GetMemeory(char* &p);則能正常運行得到結果 ThunderDownloader
14、在c++中,
const int i = 0; int *j = (int *) &i; *j = 1; printf("%d,%d", i, *j)輸出是多少?(A)
0,1
1,1
1,0
0,0
解析:
這個題一定要注意是在C++中的運行結果。
在C語言中
void main(){ const int i = 0; int *j = (int *)&i; *j = 1; printf("%d,%d", i, *j); system("pause"); }結果輸出為1,1
在C++中
#include<iostream> using namespace std; int main(void){ const int i=0; int *j = (int *)&i; *j = 1; printf("%d,%d", i, *j); system("pause"); return 0; }結果輸出為0,1
分析:C語言中的const是運行時const,編譯時只是定義,在運行才會初始化。C語言中const變量不能用于成為數組長度等作為編譯時常量的情況,原因就在此。C語言const變量在運行時改變了是可以再次讀出改變后的值的。
C++中,const變量是編譯時的常量,可以向#define定義的常量一樣使用。故C++中const變量的值在編譯時就已經確定了,直接對cosnt變量進行了值的替換,因此當const變量的值改變時,const的變量值是不會得到更新的。
這幾行代碼在C和C++中都會改變const變量的值,只不過C++中const變量在編譯的時候已經確定了,而C中的const變量可以在運行時改變后再次讀取。以下代碼核實了C++中的const變量確實被改變了。
#include<stdio.h> #include<iostream> using namespace std; int main(void){ const int i=0; int *j = (int *)&i; *j = 1;printf("%d,%d\n", i, *j); cout << "i address"<<&i << endl; cout << "j address"<<j << endl;return 0; } 同一個地址,即同一個變量。C++中const變量確實別改變了。i的值沒有更新而已。
這跟編譯器的優化編譯有關。
C++中的常量折疊:指const變量(即常量)值 放在編譯器的符號表中 ,計算時編譯器直接從表中取值,省去了訪問內存的時間,從而達到了優化。
printf("%d,%d", i, *j), 因為i是const的,第一個輸出值在編譯期間就已經被替換成0了,局部const變量放在棧區,雖不能直接修改但可以通過指針間接修改,
還要注意這是局部的const,全局的就不能修改了
15、在x86的機器上,int a=0xabcd1234 char b=((char*)&a)[0]請問b是多少(D)
0xa
0x4
0xab
0x34
解析:
x86是小端存儲,即高位存儲在高地址,低位存儲在低地址。
int a = 0xabcd1234;
內存中 ab cd 12 34,b作為一個char指針指向的地址為0x34.
高 --> 低
16、12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?(B)
120
132
145
153
解析:
C(12,6)-C(12,5)=132
卡特蘭數問題,這是我在??途W答題遇到的第三個卡特蘭數問題了,前兩個分別是50美分1美元那個排隊買票問題和6對括號的組合問題。解釋起來有點麻煩,下面慢慢解釋吧:
我們先把這12個人從低到高排列,然后,選擇6個人排在第一排,那么剩下的6個肯定是在第二排.
用0表示對應的人在第一排,用1表示對應的人在第二排,那么含有6個0,6個1的序列,就對應一種方案.
比如010101010101就對應著
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
問題轉換為,這樣的滿足條件的01序列有多少個.
觀察1的出現,顯然,在這個1之前出現的那些0,1對應的人要么是在這個1左邊,要么是在這個1前面.而且肯定要有一個0在這個1前面,也就是要求,0的個數不小于1的個數.
假設我們不考慮這個限制條件,那么全部的01排列共有C(2n,n)種,也就是一半0一半1的情況
現在我們要把其中不符合要求的數量去掉
在任何不符合條件的序列中,找出使得1的個數超過0的個數的第一個1的位置,然后在導致并包括這個1的部分序列中,以1代替所有的0并以0代表所有的1。結果總的序列變成一個有(n+1)個0和(n-1)個1的序列。而且這個過程是可逆的,也就是說任何一個有(n+1)個0和(n-1)個1構成的序列都能反推出一個不符合條件的序列,所以不符合條件的序列個數為C(2n,n-1)
所以最終結果就是C(2n,n)-C(2n,n-1)
本題中2n=12
(int *p[10])(int*) int [10]*p(int *) int (*(*p)[10])(int *) int ((int *)[10])*p以上選項都不正確
解析:
int (*(*func)[5])(int *p);
func被一個圓括號包含,左邊又有一個*,那么func是一個指針,跳出括號,右邊是一個[]運算符號,說明func是一個指向數組的指針,現在往左看,左邊有一個*號,說明這個數組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數組的元素是指向函數的指針??偨Y一下,就是:func是一個指向數組的指針,這個數組的元素是函數指針,這些指針指向具有int*形參,返回值為int類型的函數。
詳見:http://blog.csdn.net/u011385799/article/details/47783555
2、 一個進程從執行狀態轉換到阻塞狀態的可能原因是本進程(BD)。
時間片完
需要等待其他進程的執行結果
執行了V操作
執行了P操作
解析:
運行態:進程占用CPU,并在CPU上運行;
就緒態:進程已經具備運行條件,但是CPU還沒有分配過來;
阻塞態:進程因等待某件事發生而暫時不能運行; 進程在一生中,都處于上述3中狀態之一。
運行---》就緒: 時間片用完。
就緒---》運行:運行的進程的時間片用完,調度就轉到就緒隊列中選擇合適的進程分配CPU
運行---》阻塞:發生了I/O請求或等待某件事的發生
阻塞---》就緒:進程所等待的事件發生,就進入就緒隊列
P操作是阻塞作用
V操作是喚醒作用
3、已知如下代碼,并在兩個線程中同時執行f1和f2,待兩個函數都返回后,a的所有可能值是哪些?(ABCD)
int a = 2, b = 0, c = 0; void f1() { b = a * 2; a = b; } void f2() { c = a + 11; a = c; }413
15
26
解析:
考慮四行代碼的執行順序即可(1)b=a*2,c=a+11,a=c,a=b a=4
(2)b=a*2,c=a+11,a=b,a=c a=13
(3)b=a*2,a=b,c=a+11,a=c a=15
(4)c=a+11,a=c,b=a*2,a=b a=26
4、以下程序段的輸出結果是(A)
char s[]="\\123456\123456\t"; printf("%d\n",strlen(s));12
13
16
以上都不對
解析:
char s[] = "//123456/123456/t";
這樣strlen(s)輸出17.
char s[] = "\\123456\123456\t";
這樣strlen(s)輸出12.
計算字符串長度時關鍵是要注意辨認轉義字符;
含轉義字符的有:
\\ 表示字符 \
\123表示字符 {
\t 表示制表符
這些都是一個字符。
5、如下程序
#include <iostream> using namespace std;class A { public: A() { printf("A"); } };int main() { A *p1 = new A; A *p2 = (A *)malloc(sizeof(A));return 0; }該程序運行結果為(A)
A
AA
崩潰
不可預測
解析:
1 A *p1 = new A;
上面這條語句會創建一個A對象,輸出一個A;
1 A *p2 = (A *)malloc(sizeof(A));
sozeof(A)為1,這條語句創建一個大小為1的A的指針數組,但是沒有創建任何A對象,因此不輸出A
這題主要是考的new和malloc的區別,new會分配內存,并調用類的構造函數創建對象,而malloc只是分配內存,不調用類的構造函數創建對象,這個程序應該用delete p1;顯示釋放掉p1所指的堆上的內存,這樣才會調用類的析構函數,否則不會調用。
6、設有以下宏定義:
#define N 3 #define Y(n)((N+1)*n)則執行語句:z=2*(N+Y(5+1));后,z的值為:(C)
38
42
48
54
解析:
#define N 3
#define Y(n)((N+1)*n)//【注意此處n沒有加括號】,所以后面的n并不是(5+1)
z=2*(N+Y(5+1)) =2*(N+(N+1)*5+1)=2*(3+4*5+1)=48
7、 以下描述正確的是?(C)
虛函數是可以內聯的,可以減少函數調用的開銷提高效率
類里面可以同時存在函數名和參數都一樣的虛函數和靜態函數
父類的析構函數是非虛的,但是子類的析構函數是虛的,delete子類對象指針會調用父類的析構函數
以上都不對
解析:
delete子類對象是一定會調用父類的析構函數的先調用子類的析構函數然后調用父類的析構函數;如果要調用父類指向子類的對象,此時才需要父類的析構函數是虛的。
8、下列運算符中,在C++語言中不能重載的是:(C)
*
>=
::
delete
解析:
在C++中,sizeof運算符,.成員運算符,.*成員指針運算符,::作用域解析運算符以及?:條件運算符不能被重載
9、說明一下++p 與 p++ 的區別。(B)
沒有區別
++p更好一些
p++更好一些
和編譯器有關
解析:
假設這樣的一個例子:
int p = -1; int y = 0; y = p++ + ++P;先分析一下它的匯編代碼(沒有優化):
subl $40, %esp ; 分配40字節 movl $1, -16(%ebp) ; 存儲 p movl $0, -12(%ebp) ; 存儲 y movl -16(%ebp), %eax ; 這3步執行 p++ leal 1(%eax), %edx movl %edx, -16(%ebp) addl $1, -16(%ebp) ; 這2步執行 ++p movl -16(%ebp), %edx addl %eax, %edx ; 相加操作 movl %edx, -12(%ebp) ; 結果寫回 y 可以看出p++需要3步,++p需要2步,而且修改p的值是不一樣的,看出++p的效率比p++的高。
前++返回對象的引用,效率較高,故選擇++p
10、下面有關final, finally, finalize的區別描述錯誤的是?(B)
如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承
如果一個方法被聲明為final,可以被覆蓋
finally在異常處理時提供 finally 塊來執行任何清除操作。
Java使用 finalize() 方法在垃圾收集器象從內存中清除出去之前做必要的清理工作
解析:
final關鍵字可用于修飾類、變量和方法。final修飾的類不能被繼承,final修飾的方法不能被重寫,final修飾的變量不可被修改,一旦獲得初始值,該變量就不能被重新賦值。
11、 以下選項中函數形參不是指針的是?(C)
fun( int ﹡a ){…}
fun( int a [ 10 ] ) {…}
fun( int &p ) {…}
fun( int p[ ]) {…}
解析:
B選項和D選項是將數組作為函數參數;A選項是將指針作為函數參數;
C. 這個& 是引用,不是取地址.
12、下面程序應該輸出多少?(A)
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" }; char **cp[] = { c+3, c+2, c+1, c }; char ***cpp = cp; int main(void) { printf("%s", **++cpp); printf("%s", *--*++cpp+3); printf("%s", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); return 0; }POINTERSTEW
FERSTEPOINW
NEWPOINTW
POINTFIREST
解析:
這個主要是執行順序的問題,我加了一下括號:
printf("%s\n", **(++cpp));
printf("%s\n", (*(--(*(++cpp)))) + 3);
printf("%s\n", *(cpp[-2]) + 3);
printf("%s\n", cpp[-1][-1] + 1);
其中考了指針應用,隱含中也考了運算符優先級的問題(*--*++cpp+3)
c是一個指針數組,每個數組單元都是一個指針,指向一個字符創。
即c[0]="ENTER"......c[3]="FIRST"
由于[]與*運算本質幾乎是一致的,以下用[]替換*更容易理解。
c[i]=*(c+i)
c和c+i都是char*[]類型,它可以退化成char**類型,它正好是一個char**數組
cp[0]=c+3 .....cp[3]=c
引用后cp[0][0]=*(c+3)=c[3]="FIRST"
cp是char**[]類型,它可以退化成char***類型,正好與cpp類型一致。
1>++ccp的值是cp+1 *++p=*(cp+1)=cp[1] **++p=*(cp[1])=c[2]="POINT"
2>運算符優先級決定運算先后關系
++ccp的值是cp+2 *++p=*(cp+2)=cp[2]=c+1 --*++p=c *--*++p=*(c+0)=c[0]="ENTER"再+3字符串指向"ER"
3>cpp的值為cp+2 cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3再引用*(c+3)=c[3]="FIRST"字符串指到"ST"
4>cpp的值沒變,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2再[-1]得*(c+2-1)=c[1]="NEW",+1字符創指針指到"EW"
翻來覆去,記得這個換算關系式即可,c[i]=*(c+i)。
13、 有如下程序段:
void GetMemeory(char* p) { p = (char*) malloc (100); } void test() { char *str=NULL; GetMemory(str); strcpy(str,”Thunder”); strcat(str+2, “Downloader”);//*(str+2)=u;把Downloader連接到str+2的串尾后 printf(str); }請問運行Test函數結果是:(D)
Thunder Downloader
under Downloader
Thunderownloader
程序崩潰
解析:
在函數中給指針分配空間,實際上是給指針的臨時變量分配空間,函數結束后,這個臨時變量也消亡,而str仍然為NULL,沒有為其分配空間,此時strcpy()是肯定會出錯的。
若改為void GetMemeory(char* &p);則能正常運行得到結果 ThunderDownloader
14、在c++中,
const int i = 0; int *j = (int *) &i; *j = 1; printf("%d,%d", i, *j)輸出是多少?(A)
0,1
1,1
1,0
0,0
解析:
這個題一定要注意是在C++中的運行結果。
在C語言中
void main(){ const int i = 0; int *j = (int *)&i; *j = 1; printf("%d,%d", i, *j); system("pause"); }結果輸出為1,1
在C++中
#include<iostream> using namespace std; int main(void){ const int i=0; int *j = (int *)&i; *j = 1; printf("%d,%d", i, *j); system("pause"); return 0; }結果輸出為0,1
分析:C語言中的const是運行時const,編譯時只是定義,在運行才會初始化。C語言中const變量不能用于成為數組長度等作為編譯時常量的情況,原因就在此。C語言const變量在運行時改變了是可以再次讀出改變后的值的。
C++中,const變量是編譯時的常量,可以向#define定義的常量一樣使用。故C++中const變量的值在編譯時就已經確定了,直接對cosnt變量進行了值的替換,因此當const變量的值改變時,const的變量值是不會得到更新的。
這幾行代碼在C和C++中都會改變const變量的值,只不過C++中const變量在編譯的時候已經確定了,而C中的const變量可以在運行時改變后再次讀取。以下代碼核實了C++中的const變量確實被改變了。
#include<stdio.h> #include<iostream> using namespace std; int main(void){ const int i=0; int *j = (int *)&i; *j = 1;printf("%d,%d\n", i, *j); cout << "i address"<<&i << endl; cout << "j address"<<j << endl;return 0; } 同一個地址,即同一個變量。C++中const變量確實別改變了。i的值沒有更新而已。
這跟編譯器的優化編譯有關。
C++中的常量折疊:指const變量(即常量)值 放在編譯器的符號表中 ,計算時編譯器直接從表中取值,省去了訪問內存的時間,從而達到了優化。
printf("%d,%d", i, *j), 因為i是const的,第一個輸出值在編譯期間就已經被替換成0了,局部const變量放在棧區,雖不能直接修改但可以通過指針間接修改,
還要注意這是局部的const,全局的就不能修改了
15、在x86的機器上,int a=0xabcd1234 char b=((char*)&a)[0]請問b是多少(D)
0xa
0x4
0xab
0x34
解析:
x86是小端存儲,即高位存儲在高地址,低位存儲在低地址。
int a = 0xabcd1234;
內存中 ab cd 12 34,b作為一個char指針指向的地址為0x34.
高 --> 低
16、12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?(B)
120
132
145
153
解析:
C(12,6)-C(12,5)=132
卡特蘭數問題,這是我在??途W答題遇到的第三個卡特蘭數問題了,前兩個分別是50美分1美元那個排隊買票問題和6對括號的組合問題。解釋起來有點麻煩,下面慢慢解釋吧:
我們先把這12個人從低到高排列,然后,選擇6個人排在第一排,那么剩下的6個肯定是在第二排.
用0表示對應的人在第一排,用1表示對應的人在第二排,那么含有6個0,6個1的序列,就對應一種方案.
比如010101010101就對應著
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
問題轉換為,這樣的滿足條件的01序列有多少個.
觀察1的出現,顯然,在這個1之前出現的那些0,1對應的人要么是在這個1左邊,要么是在這個1前面.而且肯定要有一個0在這個1前面,也就是要求,0的個數不小于1的個數.
假設我們不考慮這個限制條件,那么全部的01排列共有C(2n,n)種,也就是一半0一半1的情況
現在我們要把其中不符合要求的數量去掉
在任何不符合條件的序列中,找出使得1的個數超過0的個數的第一個1的位置,然后在導致并包括這個1的部分序列中,以1代替所有的0并以0代表所有的1。結果總的序列變成一個有(n+1)個0和(n-1)個1的序列。而且這個過程是可逆的,也就是說任何一個有(n+1)個0和(n-1)個1構成的序列都能反推出一個不符合條件的序列,所以不符合條件的序列個數為C(2n,n-1)
所以最終結果就是C(2n,n)-C(2n,n-1)
本題中2n=12
總結
- 上一篇: 构造函数和析构函数的调用过程
- 下一篇: 部分真题整理3