數據結構填空題
題源來自《算法與數據結構考研試題精析》
一、概論
-
在數據結構中,數據的邏輯結構分 線性結構 和 線性結構 。
-
鏈接存儲的特點是利用 指針 來表示數據元之間的邏輯關系。
-
數據的物理結構包括 數據元素 的表示和 數據元素間關系 的表示。
-
對於給定的n個元素,可以構造出的邏輯結構有 集合 、 線性結構 、 樹形結構 、 圖結構 四種。
-
數據結構由數據的 邏輯結構 、 存儲結構 和 運算 三部分組成。
-
一個數據結構在計算機中的 表示 稱為存儲結構。
-
數據的邏輯結構是指 數據的組織形式,即數據元素之間邏輯關系的總體。
-
數據結構是研討數據的 邏輯結構 和 物理結構 ,以及它們之間的相互關系,並對與這種結構定義相應的 操作 ,設計出相應的 算法 。
-
抽象數據類型的定義僅取決於它的一組 邏輯特性 ,而與 在計算機內部如若表示和實現 無關,即不論其內部結構如何變化,只要它的 數學特性 不變,都不影響其外部使用。
二、線性表
-
在單鏈表中設置頭結點的作用是 有頭結點后,插入元素和刪除元素的算法統一了,不再需要判斷是否在第一個元素之前插入和刪除第一個元素。
-
根據線性表的鏈式存儲結構中每一個結點包含的指針個數,將線性鏈表分成 單鏈表 和 雙鏈表 ;而又根據指針的連接方式,鏈表又可分成 鏈表 和 靜態鏈表 。
-
鏈接存儲的特點是利用 指針 來表示數據元素之間的邏輯關系。
-
順序存儲結構是通過 結點物理上相鄰 表示元素之間的關系的;鏈式存儲結構是通過 結點指針 表示元素之間的關系的。
-
循環單鏈表的最大優點是: 從任一結點出發都可訪問到鏈表中每一個元素 。
-
指針p指向單鏈表的某個結點,在指針p所指結點之前插入s所指結點。操作序列: s->next=p->next;p->next=s;p->data<-->s->data 。這里用交換兩結點數據的辦法達到在結點前插入結點的目的。
-
判斷帶頭結點的雙循環鏈表L僅有一個元素結點的條件是 L->next->next=L&&L->prior->prior==L&&L->next!=L 。
-
帶頭結點的雙循環鏈表L為空表的條件是: L->next==L&&L->prior=L 。
-
判斷帶頭結點的單循環鏈表L僅有一個元素結點的條件是 L->next->next=L&& L-next!=L 。
三、棧和隊列
-
在棧的ADT定義中,除初始化操作外,其他基本操作的初始條件都要求 棧已存在 。
-
棧是 操作受限 的線性表,其運算遵循的原則 后進先出 。
-
堆棧是一種操作受限的線性表,它只能在線性表的 一端 進行插入和刪除操作,對棧的訪問是按照 后進先出 的原則進行的。
-
向棧中壓入元素的操作是先 進棧 ,后 退棧 。
-
當兩個棧共享一存儲區時,棧利用一維數組stack(1,n)表示,兩棧頂指針為top[1]與top[2],則當棧1空時,top[1]為 0 ,棧2空時,top[2]為 n+1 ,棧滿時為 top[1]+1=top[2] 。
-
順序棧S的GetTop(s,e)操作是用e返回s的棧頂元素。則操作正確的是 e = *(s.top)。
-
棧是一種操作受限的線性表,它只能在線性表的 棧頂 進行操作和刪除。
-
判斷順序棧是否為空的條件是 s->top == -1 ;判斷順序棧是否為滿的條件是 s.top == maxsize -1 。
-
兩個棧共享空間時棧滿的條件 兩棧頂指針相鄰 。
-
為了增加內存空間的利用率和減少溢出的可能性,由兩個棧共享一片連續的空間時,應將兩棧的 棧底 分別設在內存空間的兩端,這樣只有當 兩棧頂指針相鄰 時才產生溢出。
-
多個棧共存時,最好用 鏈式存儲結構 作為存儲結構。
-
隊列只允許在表的一端插入,插入的一端叫隊尾,刪除的一端叫隊頭。
-
順序棧用data[1..n]存儲數據,棧頂指針是top,則值為x的元素入棧的操作是 if(top!=n) data[++top]=x;
-
在按算符優先法求解表達式3-1+5x2時,最先執行的運算是 減法運算 ,最后執行的運算是 加法運算
-
循環隊列是隊列的一種 順序 存儲結構。
-
循環隊列的引入,目的是為了克服 假溢出時大量移動數據元素 。
-
在循環隊列中,隊列長度為n,存儲位置從0到n-1編號,以rear指示實際的隊尾元素,現要在此隊列中插入一個新元素,新元素的位置是 rear=(rear+1)%n 。
-
已知鏈隊列的頭尾指針分別是f和r,則將值x入隊的操作序列是 new(s);s->data=x;s->next=r->next;r->next=s;r=s;
-
區分循環隊列的滿與空,只有兩種方法,它們是 犧牲一個存儲單元 和 設標記 。
-
循環隊列用數組A[0..m-1]存放其元素值,已知其頭尾指針分別是front和rear,則當前隊列的元素個數是 (rear-front+m)%m 。
-
用循環鏈表表示的隊列長度為n,若只設頭指針,則出隊和入隊的時間復雜度分別是 O(1) 和 O(n) ;若只設尾指針,則出隊和入隊的時間復雜度分別是 O(1) 和 O(1) 。
-
設循環隊列容量為Q,當rear<front時,隊列長度為 (rear-front+Q)%Q 。
-
已知一循環隊列的存儲空間為[m..n],其中n>m,隊頭和隊尾指針分別為front和rear,則此循環隊列判滿的條件是 front==(rear+1)%(n-m+1) 。
四、樹和二叉樹
-
樹在計算機內的表示方式有 雙親鏈表表示法 , 孩子鏈表表示法 , 孩子兄弟表示法 。
-
在二叉樹中,指針p所指結點為葉子結點的條件是 p->lchild==null && p->rchlid=-null 。
-
已知完全二又樹的第8層(根結點的層次為0)有240個結點,則整個完全二叉樹的葉子結點數是 248 。
-
一個無序的元素序列可以通過構造一棵二叉排序樹而變成一個有序的元素序列 (√)
-
在順序存儲的二又樹中,編號為 i 和 j 的兩個結點處在同一層的條件是 用順序存儲結構存儲二叉樹時,要按完全二又樹的形式存儲,非完全二叉樹存儲時,要加“虛結點”。設編號為i和j的結點在順序存儲中的下標為s和t,則結點i和j在同一層上的條件是log2sHlogzt]。 。
-
若按層次順序將一棵有n個結點的完全二叉樹的所有結點從1到n編號,那么結點 i 沒有右兄弟的條件為 2*i+1>n 。
-
對於一個具有n個結點的二叉樹,當它為一棵 完全 二叉樹時具有最小高度,當它為一棵 只有一個葉子結點的二叉樹 時,具有最大高度。
-
先序遍歷森林時,首先訪問森林中第一棵樹的 根結點 。
-
前序遍歷樹林正好等同於按 前序 遍歷對應的二叉樹,后序遍歷樹林正好等同於按 中序 遍歷對應的二叉樹。
-
二又樹的先序序列和中序序列相同的條件是 任何結點至多只有右子女的二叉樹 。
-
在一棵存儲結構為三叉鏈表的二叉樹中,若有一個結點是它的雙親的左子女,且它的雙親有右子女,則這個結點在后序遍歷中的后繼結點是 雙親的右子樹中最左下的葉子結點 。
-
線索二元樹的左線索指向其 前驅 ,右線索指向其 后繼 。
-
在線索二叉樹中,T所指結點沒有左子樹的充要條件是 T->ltag =1 。
-
哈夫曼樹是 帶權路徑長度最小的二叉樹,又稱最優二叉樹 。
-
中綴式a+b3+4(c-d)對應的前綴式為++ab34-cd ,若a=1,b=2,c=3d-4,則后綴式 db/cca-b+ 的運算結果為18 。
-
已知完全二又樹的第8層(根結點的層次為0)有240個結點,則整個完全二又樹的葉子結點數是 248 。
-
深度為H的完全二叉樹至少有 2^(H-1) 個結點;至多有 2^H-1 個結點;H和結點總數N之間的關系是 H=[log2N]+1 。
-
完全二叉樹結點的平衡因子取值只可能為 1,0,-1 。
-
完全二叉樹的存儲結構通常采用順序存儲結構。(T)
-
在有N個元素的最大堆中,隨機訪問任意鍵值的操作可以在O(logN)時間完成。(F)
-
哈夫曼編碼是一種最優的前綴碼。對一個給定的字符集及其字符頻率,其哈夫曼編碼不一定是唯一的,但是每個字符的哈夫曼碼的長度一定是唯一的。(F)
五、圖
-
若一個具有n個頂點、e條邊的無向圖是一個森林,則該森林中必有 n-e 棵樹。
-
完全圖是任意兩個頂點之間存在邊 ;連通圖是任意兩個頂點之間都有路徑 。
-
有向樹定義:一個頂點的入度為0,其余頂點的入度均為 1 的有向圖。
-
在數據結構中,線性結構、樹形結構和圖形結構數據元素之間分別存在 一對一 、 一對多 和 多對多 的聯系。
-
n個頂點的連通圖至少有 n-1 條邊。n個頂點的強連通圖最少有 n 條邊。
-
在無向圖中,調用遍歷函數(BFS 或 DFS)的次數為連通分量的個數。
-
A^3【m】[n]表示從頂點 m 到頂點 n 長度為 3 的路徑一共有 A^3【m】[n]條
-
有向圖G的強連通分量是指 有向圖的極大強連通子圖 。
-
n個頂點的無向連通圖的連通分量個數為 1 個。
-
n個頂點的連通無向圖,其邊的條數至少為 n-1 。
-
對於一個具有n個頂點的無向連通圖,它包含的連通分量的個數為 1 個。
-
如果具有n個頂點的圖是一個環,則它有 n 棵生成樹。
-
最小生成樹不唯一。當帶權無向連通圖G 的各邊權值不等時 或 G只有結點數減1條邊時,MST唯一。
-
Prim算法求最小生成樹的時間復雜度是 O(V^2) 。
-
Kruskal算法求最小生成樹的時間復雜度是 O(E*logE) ,所以更適合用於 稀疏圖。
-
若無向圖滿足 n個頂點n-1條邊的無向連通圖 ,則該圖是樹。
-
n個頂點的無向圖的鄰接矩陣至少有 0 個非零元素;n個頂點的有向圖是強連通圖至少有 n 條邊。
-
N個頂點的連通圖用鄰接矩陣表示時,該矩陣至少有 2(N-1) 個非零元素。
-
鄰接矩陣法的廣度優先生成樹及深度優先生成樹唯一,鄰接表法的不唯一。
-
無向圖G有16條邊,有3個4度頂點,4個3度頂點,其余頂點的度均小於3,則圖G至少有 11 個頂點。
-
已知一個圖的鄰接矩陣表示,刪除所有從第i個結點出發的邊的方法是 將第i個非零元素都變為零元素。 。
-
在一個無向圖的的鄰接表中,若表結點的個數是m,則圖中邊的條數是 m/2 條。
-
圖的多重鄰接表表示法中,表中結點的數目是圖中邊的邊數。 (√)
-
遍歷圖的過程實質上是 查找頂點的鄰接點的過程 ,breath-first search遍歷圖的時間復雜度 O(n+e) ;depth-first search遍歷圖的時間復雜度 O(n+e) ,兩者不同之處在於 訪問頂點的順序不同 ,反映在數據結構上的差別是 隊列和棧 。
-
為了實現圖的廣度優先搜索,除了一個標志數組標志已訪問的圖的結點外,還需 隊列 以存放被訪問的結點以實現遍歷。
-
Dikstar算法是按距離源點路徑的長度小的次序產生一點到其余各定點最短路徑的算法。
-
在拓撲分類中,拓撲序列的最后一個頂點必定是的頂點 出度為0
-
拓撲排序是按AOE網中每個結點事件的最早事件對結點的進行排序。(×)
-
若網中有幾條關鍵路徑,提高一條關鍵路徑上的活動速度,不能導致整個工程縮短工期。(×)
-
AOV網中,結點表示 活動 ,邊表示 活動間的優先關系 。AOE網中,結點表示 事件 ,邊表示 活動 。
-
AOE網中,完成工程的最短時間是 從源點到匯點的最短路徑的長度。
-
在AOE(Activity On Edge)網中,從源點到匯點路徑上各個活動的時間總和最長路徑稱為 關鍵路徑 。
-
AOE-網工程工期為關鍵活動上的權之和。(T) 工期為起點到終點的最大路徑長度。
-
在AOV網中,存在環意味着 某項活動以自己為先決條件 ,這是 荒謬 的;對程序的數據流圖來說,它表明存在 死循環 。
-
當一個AOV網用鄰接表表示時,可按下列方法進行拓撲排序。
(1)查鄰接表中入度為 零 的頂點,並進;
(2)若棧不空,則①輸出棧頂元素巧,並退棧;②查i的直接后繼k,對以入度處理,處理方法是 Vk入度減1, ,若入度為 零 ,則進棧;
(3)若棧空時,輸出頂點數小於圖的頂點數,說明有 環 ,否則拓撲排序完成。
六、數組
-
對特殊矩陣壓縮可以降低運算的復雜度。 (√)
-
稀疏矩陣一般的壓縮存儲方法主要有兩種,即 三元組存儲 和 十字鏈表 。
七、查找
-
散列法存儲的思想是由關鍵字值決定數據的存儲地址。(×)
-
在哈希查找方法中,要解決兩方面的問題,它們分別是 哈希函數的選擇 及 沖突的解決。
-
在散列表中,評判一個散列函數優劣的兩個主要條件是 計算簡單 和 散列之后得到的元素分布均勻 。
-
一般線性表順序查找,查找成功的平均查找長度為 (n+1)/2 ,查找失敗的平均查找長度為 n+1 。
-
有序線性表順序查找,查找失敗時不一定要遍歷整個線性表,查找成功的平均查找長度也為 (n+1)/2 ,但查找失敗的平均查找長度為 n/2+n/n+(n+1) 。
-
采用分塊查找時,數組的組織方式為 數據分成若干塊,每塊內數據不必有序,但塊間必須有序,每塊內最大的數據組成索引塊。
-
對有65025個元素的有序順序表建立索引順序結構,在最好情況下查找到表中已有元素最多需要執行 (16) 次關鍵字比較。解析: 每個索引塊大小為 (根號下65025) = 255,塊間與塊內均使用折半查找 log255+1 = 16次,比較次數=塊間+塊內。若使用順序查找,則進行 255+1 = 256次。
八、算法填空
斐波那契數列遞歸與非遞歸實現
//遞歸實現
int Fib(int n){
if(n==0)
return 0;
else if(n==1)
return 1;
else
return Fib(n-1) + Fib(n-2);
}
//非遞歸實現
int Fib(int n){
if(n==0)
return 0;
else if(n==1)
return 1;
int a = 0;
int b = 1;
for (int i = 1; i < n; i++){
int temp = a;
a = b;
b = temp + a;
}
return b;
}
中序遍歷非遞歸算法
void InOrder2(BiTree T){
InitStack(S);
BiTree p = T;
while(p ||!isEmpty(S)){
if(p){
Push(S,p);
p = p->lchild;
}
else
{
Pop(S,p);
visit(p);
p=p->rchild;
}
}
}
層次遍歷
void levelOrder(BiTree T){
InitQueue(Q);
BiTree p;
EnQueue(Q,T);
while(!isEmpty(Q)){
DeQueue(Q,p);
visit(p);
if(p->lchild != NULL)
EnQueue(Q,P->lchild);
if(p->rchild!=NULL)
EnQueue(Q,p->rchild);
}
}
線索二叉樹
線索二叉樹結點結構
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild.*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
中序線索二叉樹線索化
void InThread(ThreadTree &p,ThreadTree &pre){
if(p!=NULL){
InThread(p->lchild,pre);
if(p->lchild == NULL){
p->lchild = pre;
p->ltag = 1;
}
if(pre!=NULL && p->rchild == NULL){
p->rchild = p;
p->rtag = 1;
}
pre = p;
InThread(p->rchild,pre);
}
}
折半查找
int Binary_Search(SeqList L, ElemType key){
int low = 0, high = L.TableLen-1,mid;
while(low<=high){
mid = (low+high)/2;
if(L.elel[mid] == key)
return mid;
else if(L.elem[mid]>key)
high = mid-1;
else
low = mid+1;
}
return -1;
}
廣度優先搜索
bool visited[MAX_TREE_SIZE];
void BFSTraverse(Graph G){
for(int i=0;i<G.vexnum;i++)
visited[i] = FALSE;
InitQueue(Q);
for(int i;i<G.vexnum;i++)
BFS(G,i);
}
void BFS(Graph G,int v){
visit(v);
visited[v] = TRUE;
EnQueue(Q,v);
while(!isEmpty(Q)){
DeQueue(Q,v);
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
if(!visited[w]){
visited[w];
visited[w] = TRUE;
EnQueue(Q,w);
}
}
}
無權圖單源最短路徑——廣搜應用
void BFS_MIN_Distance(Graph G,int u){
for(int i=0;i<G.vexnum;i++)
d[i] = MAX;
visited[u] = TRUE;
d[u] = 0;
EnQueue(Q,u);
while(!isEmpty(Q)){
DeQueue(Q,u);
for(w = FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
if(!visit[w]){
visited[w] = TRUE;
d[w] = d[u] +1;
EnQueue(Q,w);
}
}
}
深度優先搜索
bool visited[MAX_TREE_SIZE];
void DFSTraverse(Graph G){
for(int i=0;i<G.vexnum; i++)
visited[i] = FALSE;
for(int i=0;i<G.vexnum; i++)
if(!visited[i])
DFS(G,i);
}
void DFS(Graph G,int v){
visit(v);
visited[v] = TRUE;
for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
if(!visited[w])
DFS(G,w);
}
拓撲排序
bool TopologicalSort(Graph G){
InitStack(S);
for(int i=0; i<G.vexnum; i++)
Push(S,i);
int count = 0;
while(!isEmpty(S)){
Pop(S,i);
print[count++] = i;
for(p = G.Vertices[i].firstarc; p; p=p->nextarc){
v = p->adjvex;
if(!(--indegree[v]))
Push(S,v);
}
}
if(count < G.vexnum)
return false;
else
return true;
}
Prim算法——最小生成樹
void MST_Prim(Graph G){
int min_weight[G.vexnum];
int adjvex[G.vexnum];
for(int i=0; i<G.vexnum; i++){
min_weight[i] = G.Edge[0][i];
adjvex[i] = 0;
}
int min_arc;
int min_vex;
for(int i=1; i<G.vexnum; i++){
min_arc = MAX;
for(int j=1; j<G.vexnum; j++)
if(min_weight[j]!=0 && min_weight[j]< min_arc{
min_arc = min_weight[j];
min_vex = j;
}
min_weight[min_vex] = 0;
for(int j=0; j<G.vexnum; j++){
if(min_weight[j]!=0 && G.Edge[min_arc]< min_weight[j]{
min_weight[j] = G.Edge[min_arc][j];
adjvex[j] = min_arc;
}
}
}
}
Kruskal算法——最小生成樹
typedef struct Edge{
int a,b;
int weight;
};
void MST_Kruskal(Graph G,Edge* edges,int* parent){
heap_sort(edges);
Initial(parent);
for(int i=0; i<G.arcnum;i++){
int a_root = Find(parent,edges[i].a);
int b_root = Find(parent,edges[i].b);
if(a_root != b_root)
Union(parent,a_root,b_root);
}
}
//法二
typedef struct
{
int a,b;
int w;
}Road;
Road road[maxSize];
int v[maxSize];
int getRoot(int a)
{
while (a != v[a]) a = v[a];
return a;
}
void Kruskal(MGrapg g,int &sum,Road road[])
{
int i;
int N,E,a,b;
N = g.n;
E = g.e;
sum = 0;
for(i=0;i<N;++i) v[i] = i;
sort(road,E);
for(i=0;i<E;++i)
{
a = getRoot(road[i].a);
b = getRoot(road[i].b);
if(a!=b)
{
v[a] = b;
sum += road[i].w
}
}
}
Dijkstra算法——最短路徑
void Dijkstra(Graph G,int v){
int s[G.vexnum];
int path[G.vexnum];
int dist[G.vexnum];
for(int i=0;i<G.vexnum;i++){
dist[i] = G.edge[v][i];
s[i] = 0;
if(G.edge[v][i] < MAX)
path[i] = v;
else
path[i] = -1;
}
s[v] = 1;
path[v] = -1;
for(i=0;i<G.vexnum;i++){
int min = MAX;
int u;
for(int j=0;j<G.vexnum; j++)
if(s[j]==0 && dist[j]<min){
min = dist[j];
u = j;
}
s[u] = 1;
for(int j=0;j<G.vexnum;j++)
if(s[j]==0 && dist[u]+G.Edge[u][j]<dist[j]){
dist[j] = dist[u]+G.Edges[u][i];
path[j] = u;
}
}
}
Floyd算法——最短路徑
void Floyd(Graph G){
int A[G.vexnum][G.vexnum];
for(int i=0;j<G.vexnum;j++)
for(int j=0;j<G.vexnum;j++)
A[i][j] = G.edge[i][j];
for(int k=0;k<G.vexnum;k++)
for(int i=0;j<G.vexnum;j++)
for(int j=0;j<G.vexnum;j++)
if(A[i][j] > A[i][k]+A[k][j])
A[i][j] = A[i][k] + A[k][j];
}
大根堆的建立
void BuildMaxHeap(ElemType A[],int len){
for(int i=len/2; i>0 ;i--)
AdjustDown(A,i,len);
}
void AdjustDonw(ElemType A[],int k,int len){
A[0] = A[k];
for(int i=2*k;i<=len;i*=2){
if(i<len && A[i]<A[i+1])
i++;
else{
A[k] = A[i];
k=i;
}
}
A[k] = A[0];
}
void HeapSort(ElemType A[],int len){
BuildMaxHeap(A,len);
for(int i=len;i>1;i--){
Swap(A[i],A[1]);
AdjustDown(A,1,i-1);
}
}
