1. 程式人生 > >演算法與資料結構應知應會知識點

演算法與資料結構應知應會知識點

演算法與資料結構應知應會知識點
1、順序儲存結構的特點是什麼?
順序儲存時,相鄰資料元素的存放地址也相鄰(邏輯與物理的統一);要求內容中可用儲存單元的地址必須是連續的。儲存密度大(=1),儲存空間利用率高,但是插入或刪除元素時不方便。

2、鏈式儲存結構的特點是什麼?
鏈式儲存時,相鄰資料元素可隨意存放,但所佔儲存空間分兩部分,一部分存放結點值,另一部分存放表示結點間關係的指標。
插入或刪除元素時很方便,使用靈活。但是儲存密度小(<1),儲存空間利用率低。

3、順序佇列的“假溢位”是怎樣產生的?
一般的一維陣列佇列的尾指標已經到了陣列的上界,不能再有入隊操作,但其實陣列中還有空位置,這就叫做“假溢位”。採用迴圈佇列是解決假溢位的途徑。

4、如何知道迴圈佇列是空還是滿?
解決隊滿隊空的辦法有三:
①設定一個布林變數以區別隊滿還是隊空;
②浪費一個元素的空間,用於區別隊滿還是隊空;
我們常採用法②,即隊頭指標、隊尾指標中有一個指向實元素,另一個指向空閒元素。
③使用一個計數器記錄佇列中元素的個數(即佇列長度);
判斷迴圈佇列的空標誌是:f=rear 隊滿的標誌是 f=(rear+1)%N

5、常用的五種資料結構運算?
插入、刪除、查詢、修改、排序。

6、線索化二叉連結串列的基本操作函式
二:線索二叉樹

  1. 線索二叉樹的定義:n個結點的二叉連結串列中含有n+1[2n-(n-1)=n+1]個空指標域。利用二叉連結串列中的空指標域,存放指向結點在某種遍歷次序下的前驅和後繼結點的指標(這種附加的指標稱為"線索")。
    因為n個節點有2n個指標
    又因為n個節點中有n-1條邊(除了頭結點沒有邊,其餘節點都有一個父節點,相當於都有1條邊,共n-1條)
    剩下的空鏈域就是2n-(n-1)=n+1,即n+1個空指標
    2.線索二叉樹結構實現:線索化的實質就是將二叉連結串列中的空指標改為指指向前驅和後繼的線索,這種過程在遍歷二叉樹時進行

    作用:線索化的作用是將樹可以像連結串列一樣遍歷每一個節點 ,而不是用棧或遞迴的方法遍歷
    注:不同的線索化方式對應不同的線索化的遍歷(並且一棵樹只能線索化一次)
    前序線索化-----前序線索化遍歷 (根左右)
    中序線索化-----中序線索化遍歷 (左根右)
    後序線索化-----後序線索化遍歷 (左右根)
    /*
    遞迴形似完成前序遍歷
    */
    void preVisted(BitTree *root)
    {
    if(rootNULL) return ;
    printf("%d ",root->data);
    preVisted(root->lchild);
    preVisted(root->rchild);
    }
    void nonPreVisted(BitTree *root)
    {
    if(root

    NULL) return ;
    Stack s;
    init(&s);
    push(&s,root);
    while(!isEmpty(&s))
    {
    root=pop(&s);
    printf("%d ",root->data);
    if(root->rchild!=NULL) push(&s,root->rchild);
    if(root->lchild!=NULL) push(&s,root->lchild);
    }
    }

7、無向圖中的節點數量與邊的關係函式是什麼?
無向完全圖 節點數為n,則有n(n-1)/2條邊。(有向完全圖有n(n-1)條邊。

8、稀疏矩陣的基本儲存方式,三類特殊矩陣的儲存方式。
①三元組表、十字連結串列。
②對稱矩陣:aij=aji,對稱矩陣中的元素關於主對角線對稱,故儲存矩陣中上三角或下三角中的元素,每兩個對稱的元素共享一個儲存空間。這樣,能節約近一半的儲存空間。一般情況下,按行優先順序儲存主對角線(包括對角線)以下的元素。
三角矩陣:以主對角線劃分,三角矩陣有上三角和下三角兩種。右上左下。
三角矩陣中的重複元素c可共享一個儲存空間,其餘元素正好有n(n-1)/2個,因此,三角矩陣可壓縮儲存到向量sa[nx(n-1)/2+1]中,其中c存放在向量的最後一個分量中。
對角矩陣: 對角矩陣中,所有非零元素都集中在以對角線為中心的帶狀區域中,即除主對角線和主對角線鄰近的上、下方,其他元素均為0.
對角矩陣可按行優先順序或對角線的順序,將其壓縮儲存到一個向量中,並且也能找到每個非零元素與向量下標的對應關係。

9、氣泡排序、希爾排序、快速排序的實現過程
希爾排序:縮小增量排序,
思想:首先,取一個小於n的整數d1作為第一個增量,把所需的所有資料分成d1個組,所有元素位置的距離為d1的整數倍放在同一陣列中,在各組內進行直接插入排序;然後取第二個增量d2<d1,重複上述分組和排序,直至所取的增量d1=1,即把所有檔案放在同一組中進行直接插入排序為止。
我們選擇增量gap=length/2,縮小增量繼續以gap = gap/2的方式,這種增量選擇我們可以用一個序列來表示,{n/2,(n/2)/2…1},稱為增量序列。

程式碼:
void shellSort(int a[],int n)
{
int temp,i;
for(i=n/2;i>=1;i–)
{//增量序列i由n/2一次遞減直至i=1
for(int j=0;j<n-i;j++)
{//資料各組進行交換
if(a[i]>a[j+i];
a[i]=a[j+i];
a[j+i]=temp;
}
}
}
氣泡排序
它重複地走訪過要排序的數列,一次比較兩個元素,如果它們的順序錯誤就把它們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。

void bubbleSort(int data[],int n)
{
int i,j,t;
for(i=0;i<n;i++)
for(j=0;j<n-i-1;j++)
if(data[j]>data[j+1])
{
t=data[j];
data[j]=data[j+1];
data[j+1]=t;
}
}

//快速排序(老師)
快速排序又稱劃分交換排序。其基本思想:從一組待排的序列中,選一個“哨兵”,把所有
小於標兵的放在它的前面,大於標兵的放在它的後面。
通過這樣一次劃分,就把原來的序列劃分成兩個序列,然後再對左右兩邊的序列做同樣的快速排序,直至劃分後的序列只有一個元素,整個排序結束。
int quickOne(int a[],int low,int high)
{
int temp=a[low];//預設第一個為哨兵,存到一個臨時空間
while(low<high)
{//從high向左掃描,找到第一個小於哨兵的數
while(low<=high&&temp<=a[high]) high–;
a[low]=a[high];//把它存入low所指的位置;a[high]位置空間空餘
while(low<high&&temp>a[low]) low++;//從low向右掃描,找出第一個大於哨兵的元素。
a[high]=a[low];//把它存入high所指的位置;a[low]位置空間空餘
}
a[low]=temp;//基準temp已被最後定位,此時low=high;
return low;
}
void quickSort(int a[],int low,int high)
{
int i=quickOne(a,low,high);
if(low<i-1)quickSort(a,low,i-1);//遞迴初一左邊的資料
if(high>i+1)quickSort(a,i+1,high);//遞迴處理右邊的資料
}

10、常用查詢的平均查詢長度計算公式,如二分查詢、二叉排序樹查詢、線性探查法、拉鍊法
順序查詢法:ASL=(n+1)/2
二分查詢:每一次最多查2(n-1)個,ASL=(1*1+2*2+3*4+4*8+···+i*(n-2(i-1)))/n
n是總數,次數每次查詢的個數,最後一次不一定是2^(次數-1)個,是剩下的個數。別忘了除以總數。
二叉排序樹查詢:ASL=(第一次(層)查找個數+第二層查找個數+···第i層
查找個數)/總數
線性探查法、拉鍊法

11、二叉連結串列演算法
BitTree *createBitTree()
{
BitTree root=NULL;
int m;
scanf("%d",&m);
if(m>0)
{
root=(BitTree
)malloc(sizeof(BitTree));
root->data=m;
root->lchild=createBitTree();
root->rchild=createBitTree();
}
return root;
}
12、雙向連結串列的基本操作
雙鏈表,在雙鏈表中的每個結點除資料域外還有兩個指標域:一個指向其前驅結點;另一個指向其後繼結點。

13、插入排序的基本查詢次數如何計算
答案:B

//插入排序
void InsertSort(int a[],int n)
{
int i,j,temp;
for(i=1;i<n;i++)
{
temp=a[i];
j=i-1;
while(j>=0&&temp<a[j])
{
a[j+1]=a[j];
j–;
}
a[j+1]=temp;
}
}
-------------------------)

14、堆疊的基本操作
棧是一種特殊的線性表,允許插入和刪除運算的一算稱為棧頂,不允許插入和刪除運算的一算稱為棧底。
/*
棧的定義:
棧是限定在表位插入和刪除操作的線性表
允許插入和刪除的一端稱為棧頂(top),另一端稱為棧底(bottom)
不含任何資料元素的棧稱為空棧。
棧的特點:
先進後出
後進先出(Last In First Out) 簡稱LIFO結構
棧的插入操作稱為進棧,也稱為壓棧、入棧(push)
/
/鏈棧的結點/
typedef struct StackNode
{
ElementType data;//節點中儲存的元素
struct StackNode
next;//指向下一個結點的指標
}StackNode;
/鏈棧結構/
typedef struct LinkedStack
{
StackNodetop;//棧頂指標
int length;//鏈棧的長度(元素個數)
}LinkedStack;
/鏈棧的初始化/
void InitLinkStack(LinkedStack
linkedStack)
{
//1.棧頂指標指向空
linkedStack->top=NULL;
//2.長度為0
linkedStack->length=0;
}
/壓棧並返回結果/
int PushLinkedStack(LinkedStacklinkedStack,ElementType element)
{
//1.建立一個新結點
StackNode
newNode=(StackNode*)malloc(sizeof(StackNode));
newNode->data=element;
//新結點的next域指向當前的棧頂
newNode->next=linkedStack->top;
linkedStack->top=newNode;
linkedStack->length++;
return TRUE;
}
/出棧並返回出棧的元素/
int PopLinkedStacked(LinkedStacklinkedStack,ElementTypeelement)
{
if(linkedStack->top==NULL)
{
printf(“這是一個空棧,出棧操作失敗!\n”);
return FALSE;
}
//返回棧頂元素
element=linkedStack->top->data;
StackNode
node=linkedStack->top;
//棧頂指標下移一位
linkedStack->top=linkedStack->top->next;
//釋放原棧頂空間
free(node);
linkedStack->length–;
return TRUE;
}

15、廣義表的原子操作
廣義表表示
(1)廣義表常用表示
  ① E=()
 E是一個空表,其長度為0。
  ② L=(a,b)
 L是長度為2的廣義表,它的兩個元素都是原子,因此它是一個線性表
  ③ A=(x,L)=(x,(a,b))
 A是長度為2的廣義表,第一個元素是原子x,第二個元素是子表L。
  ④ B=(A,y)=((x,(a,b)),y)
  B是長度為2的廣義表,第一個元素是子表A,第二個元素是原子y。
  ⑤ C=(A,B)=((x,(a,b)),((x,(a,b)),y))
 C的長度為2,兩個元素都是子表。
  ⑥ D=(a,D)=(a,(a,(a,(…))))
 D的長度為2,第一個元素是原子,第二個元素是D自身,展開後它是一個無限的廣義表。

(2)廣義表的深度
  一個表的"深度"是指表展開後所含括號的層數。
【例】表L、A、B、C的深度為分別為1、2、3、4,表D的深度為∞。

(3)帶名字的廣義表表示
 如果規定任何表都是有名字的,為了既表明每個表的名字,又說明它的組成,則可以在每個表的前面冠以該表的名字,於是上例中的各表又可以寫成:
①E()
②L(a,b)
③A(x,L(a,b))
④B(A(x,L(a,b)),y)
⑤C(A(x,l(a,b)),B(A(x,L(a,b)),y))
⑥D(a,D(a,D(…)))
注意:
 廣義表()和(())不同。前者是長度為0的空表,對其不能做求表頭和表尾的運算;而後者是長度為l的非空表(只不過該表中惟一的一個元素是空表),對其可進行分解,得到的表頭和表尾均是空表()。
16、樹的層次與節點計算的2種演算法

17、二叉樹的三種遍歷演算法,根據其中2種遍歷結果推算出第3中遍歷結果;中序遍歷線索圖的繪製過程。
(在另一個試卷中)
18、大根堆和小根堆如何構建

Heap是一種資料結構具有以下的特點:
1)完全二叉樹;
2)heap中儲存的值是偏序;
Min-heap: 父節點的值小於或等於子節點的值;
Max-heap: 父節點的值大於或等於子節點的值;

堆的儲存:
一般都用陣列來表示堆,i結點的父結點下標就為(i–1)/2。它的左右子結點下標分別為2 * i + 1和2 * i + 2。如第0個結點左右子結點下標分別為1和2。

19、哈夫曼編碼和WPL計算
(筆記2)

20、無向圖的鄰接矩陣及其對應的順序表,從頂點A出發的深度DFS遍歷序列和廣度WFS遍歷序列
(筆記2)

21、普里姆(Prim)演算法和魯斯卡爾演算法求其最小生成樹
普里姆(Prim)演算法

從指定頂點開始將它加入集合中,然後將集合內的頂點與集合外的頂點所構成的所有邊中選取權值最小的一條邊作為生成樹的邊,
並將集合外的那個頂點加入到集合中,表示該頂點已連通.
再用集合內的頂點與集合外的頂點構成的邊中找最小的邊,並將相應的頂點加入集合中,如此下去直到全部頂點都加入到集合中,即得最小生成樹.

魯斯卡爾演算法
方法:將圖中邊按其權值由小到大的次序順序選取,若選邊後不形成迴路,則保留作為一條邊,若形成迴路則除去.依次選夠(n-1)條邊,即得最小生成樹.(n為頂點數)

步驟:

第一步:由邊集陣列選第一條邊,即權值為1的邊;

第二步:選第二條邊,即權值為2的邊;

第三步:選第三條邊,即權值為3的邊;

第四步:選第四條邊,即權值為4的邊;

第五步:選第五條邊。

22、有向圖G如下圖所示,將其看成AOE網給出關鍵路徑和關鍵路徑長度
帶權有向圖,頂點表示事件,弧表示活動。弧上的權值表示活動持續時間,此有向圖稱為AOE網,在建築學也稱為關鍵路線。AOE網常用於估算工程完成時間。

ve(j)
【含義】 事件(頂點)最早發生的時間
【解釋】這個事件(這個工作,這個工程)最早什麼時候能開始
【定性來談】ve(j)=從源點到頂點j的最長路徑長度

匯點(終點)的【最早發生時間】:即為整個工程能夠【最早完成的時間】
【解釋】中途不拖拉,一個工作完成,下一個工作立刻動手。整個工程保質保量的幹下來(效率最高),最早能夠完成的時間。我們記為plan_time,後面要用到
計算技巧:
   (1)從前向後,取大值:直接前驅結點的Ve(j)+到達邊(指向頂點的邊)的權值,有多個值的取較大者
   (2)首結點Ve(j)已知,為0
vl(k)
【含義】事件(頂點)的最遲發生時間vl(k)
【解釋】上面談到plan_time,與這個有關。假設,我們要在plan_time的時間內把整個工作做完,每個小工作最遲開始的時間稱之為【最遲發生時間】。也就是說,【小工程】最遲什麼時候開始,它不會影響總工程的按時的完成
【定性來談】vl(k)=從頂點k到匯點(終點)的最短路徑長度
最遲發生時間:Ø l(i): 若活動ai由弧<vk,vj>表示,則ai的最晚開始時間要保證事件vj的最遲發生時間不拖後。 因而有:l[i]=vl[j]-len<vk,vj>1(為邊(活動)的到達頂點的最晚發生時間減去邊的權值)
計算技巧: (1)從後向前,取小值:直接後繼結點的Vl(j) –發出邊(從頂點發出的邊)的權值,有多個值的取較小者;
   (2)終結點Vl(j)已知,等於它的Ve(j)

23、二維陣列的行優先和列優先的儲存地址的計算
行優先順序:將陣列元素按行向量排列,第i+1個行向量緊接在第i行向量之後,以二維陣列為例,按行優先順序儲存的線性序列為:
a11,a12,,a1n,a21,a22,,a2n,am1,am2,amn 列優先順序:將陣列元素按列向量排列,第j+1個列向量緊接在第j個列向量之後,A的m*n個元素按列優先順序儲存的線性序列為: a11,a21,,am1,a12,a22,,am2,,a1n,a2n,amn
二維陣列A[4][5]按行優先順序儲存,若每個元素佔2個儲存單元,且第一個元素A[0][0]的儲存地址為1000
則陣列元素A[3][2]儲存地址為?求詳解 請給詳細過程和思路解答 這種題該怎麼做?
A[i][j]的首地址 =
陣列的在記憶體中的基地址(=1000)

  • i * 列數(=5)* 每個元素佔單元數(=2)
  • j * 每個元素佔單元數(=2)
    代入得:
    A[3][2] 首地址 = 1000 + 3 * 5 *2 + 2 * 2 = 1034
    24、採用堆疊實現二叉樹的深度演算法

int Getdepth(BTree*T)
{ int ld,rd;
if(!=T) return 0;
else{
ld=Getdepth(T->lchild);
rd=Getdepth(T->rchild);
return ld>rd?(ld+1):(rd+1);
}
}
25、時間複雜度計算方法
1、常數階
首先順序結構的時間複雜度。

這個演算法的執行次數函式是f (n) =3。 根據我們推導大0階的方法,第一步就是把常數項3 改為1。在保留最高階項時發現,它根本沒有最高階項,所以這個演算法的時間複雜度為0(1)。
另外,我們試想一下,如果這個演算法當中的語句 sum = (1+n)*n/2; 有10 句,則與示例給出的程式碼就是3次和12次的差異。這種與問題的大小無關(n的多少),執行時間恆定的演算法,我們稱之為具有O(1)的時間複雜度,又叫常數階。對於分支結構而言,無論是真,還是假,執行的次數都是恆定的,不會隨著n 的變大而發生變化,所以單純的分支結構(不包含在迴圈結構中),其時間複雜度也是0(1)。
2、線性階
線性階的迴圈結構會複雜很多

3、對數階
如下程式碼:

由於每次count乘以2之後,就距離n更近了一分。 也就是說,有多少個2相乘後大於n,則會退出迴圈。 由2^x=n 得到x=logn。 所以這個迴圈的時間複雜度為O(logn)。
4、平方階
下面例子是一個迴圈巢狀,它的內迴圈剛才我們已經分析過,時間複雜度為O(n)。

而對於外層的迴圈,不過是內部這個時間複雜度為O(n)的語句,再迴圈n次。 所以這段程式碼的時間複雜度為O(n^2)。
如果外迴圈的迴圈次數改為了m,時間複雜度就變為O(mXn)。

這裡迴圈了(12+22+32+……+n2) = n(n+1)(2n+1)/6次,按照上述大O階推導方法,時間複雜度為O(n^3)。

26、資料結構的表達表示方法
?

27、帶頭結點和無頭結點的單鏈表L的判空條件
帶頭結點的單鏈表的L指向頭結點
則L->nextNULL
不帶頭結點的單鏈表的L指向第一個結點
則L
NULL

28、堆疊的基本操作演算法
/*
棧的定義:
棧是限定在表位插入和刪除操作的線性表
允許插入和刪除的一端稱為棧頂(top),另一端稱為棧底(bottom)
不含任何資料元素的棧稱為空棧。
棧的特點:
先進後出
後進先出(Last In First Out) 簡稱LIFO結構
棧的插入操作稱為進棧,也稱為壓棧、入棧(push)
/
//定義資料元素
typedef struct
{
int x;
int y;
int type;
}ElementType;
/鏈棧的結點/
typedef struct StackNode
{
ElementType data;//節點中儲存的元素
struct StackNode
next;//指向下一個結點的指標
}StackNode;
/鏈棧結構/
typedef struct LinkedStack
{
StackNodetop;//棧頂指標
int length;//鏈棧的長度(元素個數)
}LinkedStack;
/鏈棧的初始化/
void InitLinkStack(LinkedStack
linkedStack)
{
//1.棧頂指標指向空
linkedStack->top=NULL;
//2.長度為0
linkedStack->length=0;
}
/壓棧並返回結果/
int PushLinkedStack(LinkedStacklinkedStack,ElementType element)
{
//1.建立一個新結點
StackNode
newNode=(StackNode*)malloc(sizeof(StackNode));
newNode->data=element;
//新結點的next域指向當前的棧頂
newNode->next=linkedStack->top;
linkedStack->top=newNode;
linkedStack->length++;
return TRUE;
}
/出棧並返回出棧的元素/
int PopLinkedStacked(LinkedStacklinkedStack,ElementTypeelement)
{
if(linkedStack->topNULL)
{
printf(“這是一個空棧,出棧操作失敗!\n”);
return FALSE;
}
//返回棧頂元素
element=linkedStack->top->data;
StackNode
node=linkedStack->top;
//棧頂指標下移一位
linkedStack->top=linkedStack->top->next;
//釋放原棧頂空間
free(node);
linkedStack->length–;
return TRUE;
}
29、雜湊法儲存存在幾種衝突,常用的衝突處理方法有?
線上性表的雜湊儲存中,處理衝突的常用方法有()和()兩種。
開放定址法;連結法
30、共享棧的基本概念和操作
共享棧,即是兩個棧使用同一段儲存空間。
第一個棧從陣列頭開始儲存,第二個棧從陣列尾開始,兩個棧向中間拓展。
當top1+1
top2或者top1==top2-1時,即staock overflow!.
與普通棧一樣,共享棧出棧入棧的時間複雜度仍為O(1).

31、KMP演算法的特點

KMP演算法最大的特點就是指示主串的指標不需要回溯,因此指標不可能變小

32、鄰接表是一種結合了順序儲存與鏈式儲存的儲存格式,在那些結構中被使用
圖的儲存結構

33、Dijkstra方法計算有向圖G的最短路徑生成和計算