我考研時候的數據結構筆記

常用語法:

  1. 申請內存,並轉換成Person

Person *p = (Person *) malloc(sizeof(Person));

  1. 定義結構體

typedef struct {

int age;

char *name;

}Person, *PersonP,Persons[20];

如果定義的時候就是類,那麼想表示指針就得這麼寫:Person  *p

如果定義的時候就是指針,那麼想表示指針就得這麼寫: Personp  p

  1. 賦值運算

Person p;

P.age = 12;

PersonP p1 = &p;

p1 -> age = 12;

  1. 定義常量

#define MAX_VALUE 255;

  1. 入參中 &l

 表示對l進行的修改可以拿到外面去

  1. 創建數組

int *p = (int *)malloc(5 * sizeof(int));

 

1 章  緒論

考試內容:

數據結構在程序設計中的作用;數據結構的主要內容;數據結構的基本概念;算法及算法分析。

考試要求:

1. 理解數據結構的基本概念;算法設計;掌握算法的時間和空間複雜度。

2. 掌握數據結構的定義;算法的描述方法。

數據結構包括:邏輯結構、存儲結構、數據運算

算法描述方式:自然語言描述、僞代碼、程序設計語言、流程圖、SD

時間複雜度:語句被執行的次數

空間複雜度:算法消耗的存儲空間

 

 

2章  線性表  

考試內容:

線性表的邏輯結構;線性表的順序存儲結構及實現;線性表的鏈接存儲結構及實現;順序表和鏈表的比較。

考試要求:

1. 掌握線性表的概念;線性表的順序存儲結構、鏈式存儲結構及其常用算法。

2. 掌握線性表的邏輯結構;線性表的存儲結構及操作的實現;鏈式存儲結構及其常用算法;雙向循環鏈表。

常用方法:

initList(&l);

length(l);

locateElem(l,e);

getElem(l,i);

listInsert(&l,i,e);

listDelete(&l,i,&e);

printList(l);

empty(l);

destroyList(&l);

線性表包括:順序表和鏈表

#define MAX_SIZE 50

typedef struct{

ElementType data[MAX_SIZE];

int length;

}SqList;

15頁的圖

typedef struct LNode{

ElementType data;

struct LNode *next;

}LNode,*LinkList;

29頁的圖

順序表和鏈表的比較:

1.順序表可以順序存取,也可以隨機存取;鏈表只能順序存取

2.順序表的底層是數組,鏈表的底層是鏈表。相鄰元素順序表物理存儲位置相鄰,鏈表存儲位置不相鄰;

3.按值查找,順序表無序時,順序表和鏈表都是o(n)

            順序表有序時,順序表爲o(log2n),鏈表爲o(n)

 按位置查找,順序表o(1),鏈表o(n)

  1. 空間分配: 鏈表多了指針的位置,所以存儲密度小

 

雙向循環鏈表

35頁的圖

3章 棧和隊列 

考試內容:   基本運算。

2. 掌握遞歸的編程實現;循環隊列和鏈隊列的基本運算。

 

棧的名字Stack  後進先出

initStack(&s);

stackEmpty(s);

push(&s,x)

pop(&s,&x)

getTop(s,&x)

destroyStack(&s)

 

#define MAX_SIZE 50

typedef struct{

ElementType data[MAX_SIZE];

int top;

}SqStack;

 

top是棧頂的指針,初始值是-1,滿棧條件是s.top == MAX_SIZE-1;

入棧:top+1,然後s.data[s.top] = x

出棧:x = s.data[s.top]s.top-1

66頁的圖

棧的表達式求值: 一棵樹的中置表示(人類計算方式)、後置表示(計算機計算方式)

中置表示如何轉變成後置表示?

當前是數字就進棧,當前是符號就出棧兩個,並進行計算,結果進棧

 

遞歸可以用棧來轉換

 

隊列的名字Queue 先進先出

initQueue(&q)

queueEmpty(q)

enQueue(&q)

deQuque(&q)

getHead(q)

 

#define MAX_SIZE 50

typedef struct{

ElementType data[MAX_SIZE];

int front;

int rear;

}SqQueue;

 

初始時frontrear都是0,隊尾進元素,隊首出元素

入棧,rear位置添加,rear+1

出棧,front位置出值,front+1

78頁的圖

循環隊列:使用取餘%實現的

初始:front = rear = 0

添加一個元素 rear = (rear + 1)%MAX_SIZE

取出一個元素 front = (front + 1)%MAX_SIZE

隊列長度:(rear-front + MAX_SIZE)%MAX_SIZE

判斷隊列空還是滿?1.犧牲一個隊列單元;2.增加元素個數字段;3.增加tag標識上一步是添加元素還是取出元素

79頁的圖

鏈隊列

typedef struct{

ElementType data;

LNode *next;

}LinkNode;

typedef struct LinkQuquq{

LinkNode *front;

LinkNode *rear;

}LinkQueue;

81頁的圖

4章 字符串和多維數組

考試內容:

字符串;多維數組;矩陣的壓縮存儲

考試要求

1. 瞭解串的邏輯結構,存儲結構。

2.掌握串定義和存儲方法;串的操作。

 

字符串的模式匹配KMP算法

  1. 根據模求next數組

尋找當前位數前面的字符,首尾匹配,獲得匹配數+1

如果前面的字符爲空,則填寫0

2.用模和被匹配字符串進行匹配,不匹配了就去找next數組對應的值,從這一位繼續匹配

 

 

5章 樹和二叉樹

考試內容   

樹的邏輯結構;樹的存儲結構;二叉樹的邏輯結構;二叉樹的存儲結構及實現; 二叉樹遍歷的非遞歸算法;樹、森林與二叉樹的轉換。

考試要求

1.瞭解樹的基本概念;

2.理解二叉樹的性質和存儲結構;掌握遍歷、構造二叉樹和線索二叉樹;

3.理解樹的存儲結構和遍歷;掌握集合的一種表示方法;

4.掌握哈夫曼樹及其應用;

 

樹的術語:祖先、子孫、孩子、雙親、堂兄弟、度、葉子結點、終端結點、分支結點、非終端結點、根結點、深度、高度、有序樹、無序樹

二叉樹的形態:空二叉樹、只有根結點、只有左子樹、只有右子樹、左右子樹都有

特殊的二叉樹:滿二叉樹、完全二叉樹、二叉排序樹

計算:n0 = n2 + 1;度爲0的結點 = 度爲2的結點 + 1

存儲結構:順序存儲和鏈式存儲,順序存儲浪費空間,一般爲鏈式存儲

typedef struct BiTNode{

ElementType data;

BiTNode *left;

BiTNode *right;

}BiTNode,*BiTree;

二叉樹的遍歷:前序遍歷、中序遍歷、後序遍歷、層序遍歷

遍歷方式需要爲: 遞歸和非遞歸兩種

void preOrder(BiTree b){

    if(b){

       visit(b);

       preOrder(b->lchild);

       preOrder(b->rchild);

}

}

前序遍歷:構造棧,棧頂就是需要被訪問的元素

void preOrder(BiTree b){

  initStack(s);

BiTree p =b;

  while(p || !emptyStack(s)){

  If(p){

 visit(p);

 push(s,p);

 p = p->lchild;

}else{

 pop(s,p);

 p = p->rchild;

}

}

}

中序遍歷

void inOrder(BiTree b){

  initStack(s);

  BiTree p = b;

  While(p || !stackEmpty(s)){

     If(p){

        push(s,p);

        p = p->lchild;

}else{

  pop(s,p);

  visit(p);

p = p->rchild;

}

}

}

後續遍歷

void postOrder(BiTree b){

  initStack(s);

  BiTree p = b;

  BiTree r = NULL;

  while(p || !emptyStack(s)){

     if(p){

       #有左子樹就直接進棧

       push(s,p);

       p = p->lchild;

}else{

getTop(s,p)

  If(p->rchild && r != p->rchild){

    #存在右子樹且右子樹沒有訪問過

  p = p->rchild;

  push(p);

  p = p->lchild;

}else{

  #不存在右子樹,或者右子樹已經被訪問過

  pop(s,p);

visit(p);

  r = p;

  p = NULL;

}

}

}

}

 

層序遍歷

void levelOrder(BiTree b){

   initQueue(q);

   enQueue(q,b);

   while(!emptyQueue(q)){

      BiTree p = deQueue(q);

      visit(p);

      If(p->lchild){

         enQueue(q,p->lchild);

}

      If(p->rchild){

         enQueue(q,p->rchild)

}

}

}

樹和森林和二叉樹的轉化:左孩子,右兄弟

構造二叉樹的方式:

構造二叉樹的意思是說:根據兩種遍歷的結果,獲得二叉樹的邏輯結構

  1. 先序遍歷+中序遍歷
  2. 後序遍歷+中序遍歷
  3. 層序遍歷+中序遍歷

查看142的案例

線索二叉樹:如果當前結點沒有左孩子,左孩子變成直接前驅;如果當前結點沒有右孩子,右孩子變成直接後繼

ltag=0,lchild表示左孩子

ltag =1,lchild指針表示前驅

rtag=0,rchild指針表示右孩子

rtag=1,rchild指針表示後繼

typedef struct ThreadNode{

ElementType data;

int ltag;

int rtag;

struct ThreadNode *lchild;

struct ThreadNode *rchild;

}ThreadNode,*ThreadTree;

前序線索二叉樹、中序線索二叉樹、後序線索二叉樹

如何畫出中序線索二叉樹?

  1. 中序排序
  2. 尋找空指針,指向直接前驅或者直接後繼

代碼實現中序線索二叉樹(1.線索化;2.遍歷)

 

void inThread(ThreadTree &p,ThreadTree &pre){

if(p!=NULL){

inThread(p->lchild,pre);

if(p->lchild == NULL){

    #第一個的左結點也被處理了

p->ltag = 1;

p->lchild = pre;

}

if(pre!=NULL && pre->rchild == NULL){

pre->rtag = 1;

pre->rchild = p;

}

pre = p;

inThread(p->rchild,pre);

}

}

//然後最後一個結點進行特殊處理

void createInThread(ThreadThree t){

ThreadTree pre = NULL;

If(t!=NULL){

inThread(T,pre);

pre->rchild = NULL;

pre->rtag = 1;

}

}

//中序線索二叉樹的遍歷

求中序遍歷的第一個結點

ThreadNode * firstNode(ThreadNode *p){

while(p->ltag == 0){

p = p->lchild;

}

return p;

}

ThreadNode *nextNode(ThreadNode *p){

if(p->rtag == 0){

return firstNode(p->rchild)

}else{

return p->rchild;

}

}

 

void inOrder(ThreadNode *t){

for(ThreadNode *p = firstNode(t) ; p!=NULL ; p=nextNode(p)){

visit(p);

}

}

 

 

哈夫曼樹:帶權路徑長度最短的樹

  1. 將結點和權排在一起
  2. 選擇權值最小的兩個結點,連接起來,生成一個新的結點和權值
  3. 重複上面的步驟

查看190頁的圖

哈夫曼編碼:用哈夫曼樹的編碼(可變長度)

01

查看190頁的圖

 

集合:並查集

S表示森林,Root1表示以Root1爲根的樹,Root2表示以Roo2爲根的樹

並:將Root1Root2合併變爲Root1Root2作爲Root1的孩子

查:找到元素x的根是誰

初始化:讓S中所有的元素各自爲一個子集

void init(int s[]){

for(int i=0;i<max_size;i++){

s[i] = -1;

}

}

 

void find(int s[],int x){

while(s[x] >=0){

x = s[x];

}

return x;

}

 

void union(int s[],int root1,int root2){

s[root2] = root[1]

}

 

 

6章 圖    

考試內容

圖的邏輯結構;圖的存儲結構及實現;最小生成樹;最短路徑;有向無環圖及其應用。

考試要求

1.理解圖的基本概念;圖的存儲結構;

2.掌握圖的遍歷及應用{最小生成樹最短路徑等};拓撲排序和關鍵路徑。

 

G=(V,E);V表示頂點,E表示邊

V={1,2,3}表示有三個頂點

E={<1,2>,<2,1>}表示有1221的有向邊

E={(1,2)}表示12的無向邊

連通、連通圖、連通分量的概念:

頂點A和頂點B之間有路徑存在,則稱AB連通;

圖中所有的頂點都是連通的,則稱圖爲連通圖;

一個圖中的極大連通子圖,叫做連通分量。

圖的存儲結構:臨接矩陣法、臨接表法、十字鏈表、臨接多重表

鄰接矩陣

typedef struct {

vertexType vex[MAX_SIZE];

edgeType edge[MAX_SIZE][MAX_SIZE];

int vexnum;

int arcnum;

}MGraph;

 

臨接表法

邊結點

typedef struct ArcNode{

int adjvex;

struct ArcNode *next;

}ArcNode;

頂點

Typedef struct VNode{

VertexType data;

ArcNode *first;

}VNode,AdjList[MAX_SIZE];

Typedef struct {

AdjList vertexList;

int vexNum;

int arcNum;

}AlGraph;

 

十字鏈表:(有方向圖)

VNodedatainout

ArcNodeinDataoutDatainout

 

臨接多重表:(無方向圖)

VNodedatanext

ArcNodeinDatainoutDataout

 

圖的基本操作:

getEdgeValue(G,x,y);

setEdgeValue(G,x,y);

insertVertex(G,x);

deleteVertex(G,x);

addEdge(G,x,y);

removeEdge(G,x,y);

neighbors(G,x);

firstNeighbor(G,x)

nextNeighbor(G,x,y);

adjacent(G,x,y);

 

圖的遍歷:廣度優先和深度優先

下面是廣度優先的算法,需要一個visited[]數組和一個queue來做輔助

bool visited[MAX_NUM] = false;

void bfsMain(Graph g){

for(int i=0;i<g.vertexNum;i++){

visited[i] = false;

}

for(i=0;i<g.vertexNum;i++){

if(!visited[i]){

bfs(g,i)

}

}

}

void bfs(Graph g,int v){

initQueue(q);

visit(v);

visited[v]=true;

enqueue(v);

while(!emptyQueue(q)){

dequeue(q,v);

for(int i = firstNeighbor(g,v);i>0;i=nextNeighbor(g,v,i)){

if(!visited(i)){

visit(i);

visited[i]=true;

enQueue(i);

}

}

}

}

廣度優先算法分析:

時間複雜度是O(V+E)或者O(V平方)

空間複雜度是O(V)

 

深度優先:

bool visited[MAX_SIZE];

void dfsMain(Graph g){

for(int i=0;i<g.vertexNum;i++){

visited[i] = false;

for(i=0;i<g.vertexNum;i++){

dfs(g,i);

}

}

}

void dfs(Graph g,int v){

visit(v);

visited[v]=true;

for(int w = firstNeighbor(g,v);w>0;w=nextNeighbor(g,v,w)){

if(!visited[w]){

dfs(g,v);

}

}

}

深度優先算法分析:

時間複雜度是O(V+E)或者O(V平方)

空間複雜度是O(V)

 

最小生成樹的算法:普里姆和克魯斯卡爾

普里姆:1.任選一點;2.尋找當前圖形的權最短的邊的未連接的點,加入進來;無限循環

克魯斯卡爾:每次都找最小權值的邊,查看當前的邊的兩端點是否在樹內,不在則加入進來

看書239

 

最短路徑的算法:迪傑斯特拉和弗洛伊德

迪傑斯特拉P241

求頂點1到其餘頂點的距離:

做表,縱座標是頂點2345;集合

橫左邊是第一輪,第二輪,第三輪。。。

每次把上一輪確定進入集合的點加入到已知路徑的中間;求得最短路徑並加入集合

弗洛伊德看總結的案例

迪傑斯特拉和弗洛伊德的算法都是貪心算法,需要先求出當前的路徑中經過的點,再把下一個點加入進來,需要整合計算

 

拓撲結構

給一個有向的樹形結構,依次寫出沒有指向它的頂點。

 

關鍵路徑

有四個量:事件最早發生時間、事件最遲發生時間、活動最早開始時間、活動最遲結束時間。

  1. 畫圖,圓圈和方塊
  2. 圓圈畫出事件的最早發生時間和最遲發生時間
  3. 方塊畫出活動的最早開始時間和最遲結束時間
  4. 做表

 

7章 查找技術   

考試內容

查找的基本概念、查找算法的性能;線性表的查找技術;樹表的查找技術;散列表的查找技術

考試要求

1掌握順序查找、折半查找和索引查找的方法

2.掌握二叉排序樹的構造方法和二叉平衡樹的建立方法

3.掌握哈希表的構造方法,哈希表在查找不成功時的平均查找長度的計算方法

 

順序查找: 一般線性表的順序查找、有序表的順序查找、有序表的二分查找

typedef struct SSTable{

ElementType *data;

int length;

}SSTable;

 

int search(SSTable ss,ElementType key){

ss.data[0] = key;

for(int i = ss.length;ss.data[i]!=key;i--){

//哨兵 + 從後往前找

}

return i;

}

二分查找

int binarySearch(SeqList l,ElementType key){

int low = 0;int high = l.length-1;

int middle;

while(high >= low){

middle = ( low + high ) / 2;

if(l[middle] == key){

return middle;

}

if(l[middle] > key){

high = middle -1;

}else{

low = middle + 1;

}

}

return -1;

}

索引查找又叫做分塊查找

 

散列表:包括hash函數和處理衝突的方式

常用的散列函數:直接地址法、除留餘數法、數字分析法、平方取中法

處理衝突的方法:開放地址法,拉鍊法

散列表的性能比較:ASL和α

ASL1.先寫出具體的數組;2.寫出某個數查詢的次數;3.ASL等於平均查找次數

α裝填因子 = 表中記錄數/數組的長度

 

二叉排序樹和二叉平衡樹

二叉排序樹:中序排序,左子樹均小於父結點,右子樹均大於父結點

int search(BiTree t,ElementType key){

while(t!=null && t->data!=key){

if(t->data < key){

t = t->rchild;

}else{

t = t->rchild;

}

}

return t;

 

}

int insertBSTNode(BiTree &t,ElementType key){

if(t == NULL){

t = (BiTree *)malloc(sizeof(BiTree));

t->data = key;

t>lchild = NULL;

t->rchild = NULL;

return 1;

}

if(key == t->data){

return 0;

}else if(key > t->data){

return insertBSTNode(t->rchild,key);

}else if(key < t->data){

return insertBSTNode(t->lchild,key);

}

}

二叉排序樹的刪除操作:

1.如果刪除葉子結點,則直接刪除

2.如果刪除的結點只有1個左孩子或者右孩子,則刪除該結點後孩子頂替

3.如果刪除的結點有左孩子和右孩子,則將直接前驅結點或者直接後繼結點頂替

 

平衡二叉樹

概念:結點的左子樹和右子樹高度差不超過1

插入:LL   LR  RL  RR四種情況

P186頁  RLLR都是以RLLR爲父結點,LLRR是以LR爲父節點

 

 

8章 排序技術    

考試內容

排序的基本概念、排序算法的性能;插入排序;交換排序;選擇排序;歸併排序; 分配排序;各種排序方法的比較。

考試要求

1.掌握各類排序的原理和特徵;

2. 掌握排序的各種算法實現和應用

 

排序的口訣:

選擇插入歸交基(排序的種類分爲選擇、插入、交換、歸併、基數)

插入裏有直半希(插入排序包括:直接插入、折半、希爾)

交換冒泡快排好(交換排序包括:冒泡、快排)

選出一堆簡單慄(選擇排序包括:簡單選擇、堆排)

 

穩定:

穩穩的幸福,雞毛插歸殼(插入、歸併)

 

額外的存儲:

有序插,無序快

 

O(nlog2n)

快以nlog2n歸堆(快排,歸併、堆排)

 

插入排序:將數分成三部分:已經排好序的、正在排序的、未排序的

 

快排:在一堆成績裏面第一次排序就可以得到張碩士的成績排名,需要ijpivot三個指針,i在最左邊,pivot在最左邊,j在最有邊。從j開始運動,ji的方向運動,ij的方向運動。當j碰到比pivot小的數就停止運動,且將該值放到i上,i碰到比pivot大的數就停止運動,且將該值放到j上。一直運動直到ij位置相等,此時將pivot賦值到ij位置上。Pivot的排名得以確定。

空間複雜度O(log2n)

 

堆排序:

堆排序分爲大根堆和小根堆,大根堆就是父節點比子節點大

1.建堆

只處理分支結點的逆層序排序 O(n)

2輸出堆結點,然後將最底層的結點放到根節點,然後建堆

3新增結點放到最底層,然後逆序排序

 

歸併排序:

1先把兩兩一組排序

2.再把四個一組排序

3.再把八個一組排序

空間複雜度O(n)

 

基數排序:面向數字進行排序

比如n個三位數字的排序:

需要三次分配三次收集

每次分配需要n次,每次收集需要d10)次

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章