今天的主題是:數據結構與算法;按老規矩給一張知識導圖:
1.設n是描述問題規模的非負整數,下列程序段的時間復雜度是()。
x=0;
while(n>=(x+1) * (x+1) )
x=x+1;
A.O(log2^(n)) B.O(n^1/2) C.O(n) D.O(n^2)
解析:循環條件是n>=(x+1)^2,循環執行的次數是[n^1/2],因此時間復雜度是O(n^1/2)。
2.下列函數的時間復雜度是()。
int func(int n){
int i=0,sum=0;
while(sum<n)
sum+=++i;
return i;
}
A.O(log2^(n)) B.O(n^1/2) C.O(n) D.O(nlog2^(n))
解析:sum+=++i可以分解為兩條語句,即++i和sum=sum+i,則該while循環中,1+2+3+……+i<n,即i(i+1)/2<n,因此時間復雜度是O(n^1/2)。
3.下列程序段的時間復雜度是()。
count=0;
for(k=1;k<=n;k∗=2)
for(j=1;j<=n;j++)
count++;
A.O(log2^(n)) B.O(n) C.O(nlog2^(n)) D.O(n^2)
解析:這是一個雙重for循環嵌套的程序。在內層循環中,每次循環j都自增1,每次內層循環執行n次,時間復雜度是O(n);在外層循環中,每次循環的增量定義為k∗=2,時間復雜度是O(log2^(n))。因此這個程序段的時間復雜度是O(n)∗O(log2^(n)),即O(nlog2^(n))。
4.下列T(n)表示各算法中最耗時操作的執行次數,n表示數據量,請按照時間復雜度從小到大排列()。
T1(n)=100n+200log2^(n) T2(n)=3n^2 T3(n)=10000000 T4(n)=300log2^(n)
解析:當n充分大時,函數的增長關系為c<log2^(n)<n<n^2(c是與n無關的任意整數),因此T3<T4<T1<T2。
5.下列關於數據的邏輯結構的敘述中,不正確的是()。
A.數據的邏輯結構是數據間關系的描述
B.線性表是典型的線性結構
C.數據的邏輯結構分為線性結構和非線性結構
D.數據的邏輯結構不僅反映數據間的邏輯關系,而且包含其在計算機中的存儲方式
解析:數據的邏輯是依據具體問題的需要而建立的數據元素和它們之間的關系,它只抽象地反映數據元素之間的邏輯關系,而與其在計算機中的存儲方式無關。數據的存儲結構是依據具體問題所要求的響應速度,處理時間,修改時間,存儲空間等來實現數據的邏輯結構,是指數據邏輯結構的存儲方式。數據的邏輯結構分為線性結構和非線性結構。線性結構包括線性表,棧,隊列等。
6.關於數據結構的描述,正確的是()。
A.數據的邏輯結構可以划分為線性結構,樹形結構和索引結構
B.一種邏輯結構可采用多種存儲結構實現
C.一種存儲結構只能實現一種邏輯結構
D.現實世界中數據對象的一對多聯系可以采用線性結構表達
解析:數據的邏輯結構分為線性結構,樹形結構,圖形結構和集合;一種邏輯結構可采用多種不同的存儲結構實現,如線性表可采用順序存儲結構和鏈式存儲結構實現;一種存儲結構可以實現多種邏輯結構,如鏈式存儲結構可以實現單鏈表,二叉鏈表等;線性結構的元素之間是一對一聯系,而樹形結構的元素之間是一對多聯系,圖狀結構的元素之間是多對多聯系。
7.已知表頭元素為c的單鏈表在內存中的存儲狀態如下表所示。
地址 | 元素 | 鏈接地址 |
1000H | a | 1010H |
1004H | b | 100CH |
1008H | c | 1000H |
100CH | d | NULL |
1010H | e | 1004H |
1014H |
現將f存放於1014H處並插入到單鏈表中,若f在邏輯上位於a和e之間,則a,e,f的“鏈接地址”依次是()。
解析:單鏈表的每個結點包含數據域和指針域,其中鏈接地址存放在指針域中,即下一個結點的地址。如圖所示:
在插入f之后,a指向f,f指向e,e指向b。a的鏈接地址為f的內存地址,即1014H;e的鏈接地址為b的內存地址,即1004H;所以“鏈接地址依次是1014H,1004H,1010H”。
8.已知一個帶有表頭結點的雙向循環鏈表L,結點結構為
prev | data | next |
其中,prev和next分別是指向其直接前驅和直接后繼結點的指針。現要刪除指針p所指的結點,正確的語句序列是()。
A.p->next->prev=p->prev; p->prev->next=p->prev; free(p);
B.p->next->prev=p->next; p->prev->next=p->next; free(p);
C.p->next->prev=p->next; p->prev->next=p->prev; free(p);
D.p->next->prev=p->prev; p->prev->next=p->next; free(p);
解析:雙向循環鏈表的刪除與單鏈表類似,都是使得鏈表不斷開。雙向循環鏈表刪除指針p所指的結點,先將p所指的結點的直接后繼的前驅指針指向p所指結點的直接前驅,即p->next->prev=p->prev;再將p所指結點的直接前驅的后繼指針指向p所指結點的直接后繼,即p->prev->next=p->next;最后再刪除指針p所指的結點,即free(p);
9.某線性表中最常用的操作是在最后一個元素之后插入一個元素和刪除第一個元素,則采用()存儲方式最節省運算時間。
A.單鏈表 B.僅有頭指針的單循環鏈表 C.雙鏈表 D.僅有尾指針的單循環鏈表
解析:采用帶有尾指針鏈表可以快速找到尾結點,方便在線性表的最后一個元素之后插入一個元素。采用僅有尾指針的單循環鏈表,尾結點的下一個結點就是頭節點,可以快速刪除第一個元素。因此,采用僅有尾指針的單循環鏈表時,在最后一個元素之后插入一個元素和刪除第一個元素的時間性能都是O(1),最節省運算時間。
10.指針p1和p2分別指向兩個無頭結點的非空單循環鏈表中的尾結點,要將兩個鏈表鏈接成一個新的單循環鏈表,應執行的操作為()。
A.p1->next=p2->next; p2->next=p1->next;
B.p2->next=p1->next; p1->next=p2->next;
C.p=p2->next; p1->next=p; p2->next=p1->next;
D.p=p1->next; p1->next=p2->next; p2->next=p;
解析:引入指針p用於保存p1所指結點的后繼結點,即p=p1->next; 再將p1所指結點的后繼指針指向p2所指結點的后繼結點,即p1->next=p2->next; 最后將p2所指結點的后繼指針指向p所指結點p2->next=p;。這樣就可以將兩個非空單循環鏈表鏈接成一個新的單循環鏈表。
11.定義三元組(a,b,c)(a,b,c均為整數)的距離D=|a-b|+|b-c|+|c-a|。給定義3個非空整數集合S1,S2和S3,按升序分別存儲在3個數組中。請設計一個盡可能高效的算法,計算並輸出所有可能的三元組(a,b,c)(a∈S1,b∈S2,c∈S3)中的最小距離。例如,S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41},則最小距離為2,相應的三元組為(9,10,9)。
要求:(1)給出算法的基本設計思想。(2)根據設計思想,采用C或C++語言描述算法,關鍵之處給出注釋。
(3)說明你所設計算法的時間復雜度和空間復雜度。
解析:(1)算法的基本設計思想如下:
- 定義int型變量min用於存放當前所有已處理過的三元組中的最小距離,初值為C語言能表示的最大整數INT_MAX。
- 使用數組A,B,C分別存儲非空整數集合S1,S2,S3,3個集合的元素個數(即數組的長度)分別為x,y,z;3個數組的下標變量分別為i,j,k,初值均為0.
- 當i<x且j<y且k<z且min>0時,循環執行4~6。
- 計算三元組(A[i],B[j],C[k])的距離D。
- 若D<min,則min=D,使min始終存放最小距離。
- 將A[i],B[j],C[k]中的最小值的下標加1。
- 返回最小距離min,算法結束。
(2)采用C語言描述算法,代碼如下:
(3)將集合S1,S2,S3的元素個數(即數組的長度)分別記為x,y,z,時間復雜度是O(x+y+z),空間復雜度是O(1)。
12.設線性表L=(a1,a2,a3,……,an)采用帶頭結點的單鏈表保存,鏈表中結點定義如下:
typedef struct node{
int data;
struct node ∗next;
}NODE;
請設計一個空間復雜度為O(1)且時間上盡可能高效的算法,重新排列L中的各節點,得到線性表L'=(a1,an,a2,a(n-1),a3,…)。要求:
(1)給出算法的基本設計思想。
(2)根據設計思想,采用C或者C++語言描述算法,關鍵之處給出注釋。
(3)說明你所設計的算法的時間復雜度。
解析:(1)算法的基本設計思想如下:
- 設置兩個指針p和q交替前行,尋找單鏈表的中間結點。
- 將單鏈表的后半段鏈表原地逆置。
- 從單鏈表前,后段中依次各取一個結點按要求排列。
(2)采用C語言描述算法,代碼如下:
如果對單鏈表原地逆置不了解,可以看一位博主的文章:單鏈表原地逆置 - 潭影空心 - 博客園 (cnblogs.com)
(3)算法的時間復雜度為O(n)。