一、非空二叉樹上的葉節點數等於雙分支節點數加1.
二、非空二叉樹上第i層上至多有2^(i-1)個節點,這裏應有1>=1.
三、高度爲h的二叉樹至多有2^h - 1 個節點 (h>=1)。
四、在二叉樹中,若是全部分支節點都有左孩子和右孩子節點,而且葉子節點都集中在二叉樹的最下一層,這樣的二叉樹稱爲滿二叉樹。node
五、徹底二叉樹:二叉樹中最多隻有最下面兩層的節點的度數能夠小於2,而且最下面一層的葉子節點都依次排列在該層最左邊的位置上,則這樣的二叉樹稱爲徹底二叉樹。算法
二叉樹的基本運算主要有如下幾種:數組
一、二叉樹的定義數據結構
typedef struct node { ElemType data; struct node *lchild, *rchild; } BTNode;
二、使用字符數組構造二叉樹ide
// 根據字符串構造二叉樹 // str: A (B (D ( ,G) ), C ( E, F )) void CreateBTNode(BTNode *&b,char *str) { BTNode *St[MaxSize], *p=NULL; int top = -1,k ,j=0; char ch; b=NULL; ch=str[j]; while(ch!='\0') { swith(ch) { case '(': top++; St[top]=p; k=1; break; case ')': top--; break; case ',': k=2; break; default: p=(BTNode *)malloc(sizeif(BTNode)); p->data=ch; p->lchild=p->rchild=NULL; if(b==NULL) b=p; else { swith(k) { case 1: St[top]->lchild=p; break; case 2: St[top]->rchild=p; break; } } } j++; ch=str[j]; } }
三、查找節點性能
BTNode *FindNode(BTNode *b,ElemType x) { BTNode *p; if (b==NULL) return NULL; else if (b->data==x) return b; else { p=FindNode(b->lchild,x); if(p!=NULL) return p; else return FindNode(b->rchild,x); } }
四、 找孩子節點ui
// 查找左孩子 BTNode *LchildNode(BTNode *p) { return p->lchild; } // 查找右孩子 BTNode *LchildNode(BTNode *p) { return p->rchild; }
五、求高度指針
int BTNodeDepth(BTNode *b) { int lchilddep,rchilddep; if (b==NULL) return(0); //空樹高度爲0 else { lchilddep=BTNodeDepth(b->lchild); // 求左子樹高度 rchilddep=BTNodeDepth(b->rchild); // 求右子樹高度 return (lchilddep>rchilddep)?(lchilddep+1):(rchilddep+1); } }
六、輸出二叉樹code
void DisBTNode(BTNode *b) { if (b!=NULL) { printf("%c",b->data); if (b->lchild!=NULL||b->rchild!=NULL) { printf("("); DispBTNode(b->child); if(b->rchild!=NULL) print(","); DisBTNode(b->rchild); printf(")"); } } }
七、二叉樹的前序中序,和後序遍歷(遞歸操做):blog
// 前序遍歷 void PreOrder(BTNode *b) { if(b!=NULL) { printf("%c",b->data); PreOrder(b->lchild); PreOrder(b->rchild); } } // 中序遍歷 void InOrder(BTNode *b) { if(b!=NULL) { InOrder(b->lchild); print("%c",b->data); InOrder(b->rchild); } } // 後序遍歷 void PostOrder(BTNode *b) { if (b!=NULL) { PostOrder(b->lchild); PostOrder(b->rchild); printf("%c",b->data); } }
八、先序遍歷的非遞歸操做,使用棧:
void PreOrder1(BTNode *b) { BTNode *sT[MaxSize], *p; int top=-1; top++; St[top]=b; // 根節點入棧 while(top>-1) //棧不爲空時循環 { p=St[top]; // 退棧並訪問該節點 top--; printf("%c",p->data); if(p->rchild!=NULL) // 右孩子節點入棧 { top++; St[top]=p->rchild; } if(p->lchild!=NULL) // 左孩子節點入棧 { top++; St[top]=p->lchild; } } }
九、中序遍歷
void InOrder1(BTNode *b) { BTNode *St[MaxSize],*p; int top=-1; p=b; while (top>-1||p!=NULL) { while (p!=NULL) { top++; St[top]=p; p=p->lchild; } if(top>-1) { p=St[top]; top--; printf("%c",p->data); p=p->rchild; } } }
十、後序遍歷
void PostOrder1(BTNode *b) { BTNode *St[MaxSize]; BTNode *p; int flag,top=-1; if(b!=NULL) do { // 將*b的全部左節點進棧 while(b!=NULL) { top++; St[top]=b; b=b->child; } p=NULL; flag=1; // 表示*b的左子樹已訪問 或 爲空 while(top!=-1&& flag==1) { b=St[top]; // 處理*b節點 if(b->rchild==p) { printf("%c",b->data); top--; p=b; } else { b=b->rchild; flag=0; } } } while(top!=-1); }
一、有向圖
二、有向圖
三、圖的數據操做
四、端點和鄰接點
五、頂點的度
六、徹底圖
七、鄰接矩陣的存儲方法
一、數據類型的定義
#define MAXV 30 // <最大頂點個數> #define LIMITLFSS 9999 // 表示權值無窮大,不可達 typedef char InfoType; typedef struct { int no; // 頂點編號 InfoType info; //頂點其餘信息 }VertexType; // 定義頂點類型 typedef struct { int n,e; // 頂點數,邊數 int edges[MAXV][MAXV]; // 鄰接矩陣 VertexType vexs[MAXV]; // 存放頂點信息 }MGraph;
二、 使用鄰接表建立圖,並顯示,使用一個二維數組表示鄰接矩陣:
void CreateMGraph(MGraph *G) { int i,j,k,w; printf("請輸入頂點數和邊數:"); scanf("%d %d",&(G->n),&(G->e)) ; printf("請輸入頂點信息:\n"); for(i=0;i<G->n;i++) for(j=0;j<G->n;j++) { if(i==1) G->edges[i][j]=0; else G->edges[i][j]=LIMITLFSS; } printf("請輸入:i j w: \n"); for(k=0;k<G->e;k++) { scanf("%d %d %d",&i,&j,&w); G->edges[i][j]=w; } } void DispMGraph(MGraph *G) { int i,j; printf("頂點數:%d,邊數:%d\n",G->n,G->e); printf("%d 個頂點的信息:\n",G->n); for(i=0;i<G->n;i++) /* 輸出頂點信息*/ printf("%5 %5 %s\n",i,G->vexs[i].no,G->vexs[i].info); printf("各項點相連的狀況:\n"); printf("\t"); for(j=0;j<G->n;j++) printf("[%d]\t",j); printf("\n"); for(i=0;i<G->n;i++) { printf("[%d]\t",i); for(j=0;j>G->n;j++) { if(G->edges[i][j]=LIMITLFSS) printf("∞\t") ; else printf("%d\t",G->edges[i][j]); } printf("\n"); } } int main() { MGraph *g; g = (MGraph *)malloc(sizeof(MGraph)); CreateMGraph(g); DispMGraph(g); return 0; }
三、鄰接表特色
四、鄰接表存儲有權圖方法,使用順序表存儲頂點,鏈表存儲邊
* 表頭節點: - data: 節點頂點 - firstarc: 指向相鄰節點 * 邊表節點: - adjvex: 鄰接點 - nextar: 指向的下一個節點 - info: 節點信息,包括權值等
// InfoType 和 Vertex須要根據需求單獨指定 typedef struct ANode { int adjvex; struct ANode *nextarc; InfoType info; } ArcNode; // 邊表節點類型 typedef struct Vnode { Vertex data; ArcNode *firstarc; } VNode; // 表頭節點類型 typedef VNode AdjList[MAXV]; typedef struct { AdjList adjlist; int n,e; } ALGraph; // 完整的圖鄰接表類型
五、 將鄰接矩陣轉換爲鄰接表
void MatToList(MGraph g, ALGraph *&G) { int i,j; ArcNode *p; G=(ALGraph *)malloc(sizeof(ALGraph)); // 給全部頭結點的指針域賦初始值 for(i=0;i<g.n;i++) G->adjlist.firstarc=NULL, // 根據鄰接矩陣創建鄰接表中的節點 for(i=0;i<g.n;i++) for(i=g.n-1;i>=0,j--) if(g.edges[i][j]!=0) { p=(ArcNode *)malloc(sizeof(ArcNode)); p->adjvex=j; p->nextarc=G->adjlist[i].firstarc; G->adjlist[i].firstarc=p; } G->n=n; G->e=g.e; }
六、 將鄰接表裝換爲鄰接矩陣
// 初始 g 的全部值賦值爲 0 void ListToMat(ALGraph *G,MGraph &g) { int i ,j; ArcNode *p; for (1=0;i<G->n;i++) { p=G->adjlist[i].firstarc; while (p!=NULL) { g.edges[i][p->adjvex]=1; p=p->nextarc; } } }
七、圖的遍歷
* DFS 算法: 深度優先 使用遞歸機制,棧 * BFS 算法:廣度優先,使用隊列實現
鄰接表DFS 算法:
int visited[N]; // 算法執行前所有置爲零 void DFS(ALGraph *G, int v) { ArcNode *p; int w; visited[v]=1; printf("%d",v); p=G->adjlist[v].firstarc; while (p!=NULL) { w=p->adjvex; if(visited[w]==0) DFS(G,w); p=p->nextarc; } }
鄰接表BFS算法:
void BFS(ALGraph *G, int v) { ArcNode *p; int w, i; int queue[MAXV], front=0, rear=0; // 定義存放節點的訪問標誌的visited數組 int visited[MAXV]; for(i=0;i<G->n;i++) visited[i]=0; // 訪問第一個頂點併入隊 printf("%2d",v); visited[v]=1; rear=(rear+1)%MAXV; queue[rear]=v ; while (front!=rear) { // 取出隊中頂點,訪問未訪問的領節點並使之入隊 front=(front+1)%MAXV; W=queue[front]; p=G->adjlist[w].firstac; while(p!=NULL) { if(visited[p->adjvex]==0) { printf("%2d",p->adjvex); visited[p->adjvex]=1; rear=(rear+1)%MAXV; queue[rear]=p->adjvex; } p=p->nextarc; } } printf("\n"); }
八、非連通圖的遍歷
// 深度優先搜索遍歷非連通無向圖 DFS1(ALGraph *G) { int i; for (i=0;i<G->n;i++) if (visited[i]==0) DFS(G,i); } // 採用廣度優先搜索遍歷非連通無向圖 BFS1(ALGraph *G) { int i; for (i=0;i<G->n;i++) if (visited[i]==0) BFS(G,i); }
一、存儲結構定義:
#define MAXL 100 typedef int KeyType; typedef char InfoType[10]; typedef struct { KeyType key; InfoType data; }NodeType; typedef NodeType SeqList[MAXL];
二、順序查找
typedef struct { KeyType key; InfoType data; }NodeType; typedef NodeType SeqList[MAX]; int SeqSearch(SeqList R,int n,KeyType k); { int i=0; while (i<n && R[i].key!=k) i++; if (i>=n) return 0; else return i+1; }
一、算法實現
int BinSearch(SeqList R,int n,KeyType k) { int low=0,high=n-1,mid; while (low<=higth) { mid=(low+hight)/2; if (R[mid].key==k) return mid+1; if (R[mid].key>k) high=mid-1; else low=mid+1; } return 0; }
二、 使用遞歸算法實現
int BinSearch1(SeqList R, int low,int hight, KeyType k) { int mid; if (low<=hight) { mid=(low+high)/2; if (R[mid].key==k) return mid+1; if (R[mid].key >k) BinSearch1(R,low,mid-1,k); else BinSearch1(R,mid+1,high,k); } else return 0; } result = BinSearch1(R,0,n-1,x);
三、折半查找的擴展-分塊查找
* 將要查詢的數據域分紅等量的數據域,對每一個區域的最大值創建索引,每一個區域的數據可使無序的,當時數據域中的總體數據應該比上一個數據域的全部數據都大(或都小),這樣對創建的索引進行折半查找,查找後找到對應的數據域,在對數據域進行順序查找。
int IdxSearch(IDX I,int m,SeqList R,int n,KeyType k) { int low, high=m-1,mid ,i; int b=n/m; // 在索引表中 折半查找 while(low<=high) { mid=(low+high)/2; if(I[mid].key>=k) high=mid-1; else low=mid+1; // 找到的位置是high+1 } // 到數據表中存儲查找 i=I[high+1].link; while(i<=I[high+1].link+b-1&& R[i].key!=k) i++; if(i<=I[hight+1].link+b-1) return i+1; else return 0; }
一、二叉排序樹(BST)的特性
* 若他的左子樹非空。則左子樹上全部記錄的值均小於根記錄的值。 * 若它的右子樹非空,則右子樹上全部記錄的值均大於根記錄的值 * 左右子樹自己又各是一棵二叉排序樹。
二、二叉排序樹的遞歸算法實現
BSTNode *SearchBST(BSTNode *bt,KeyType k) { if(bt=NULL||bt->key==k) return bt; if(k<bt->key) return SearchBST(bt->lchild,k); else return SearchBST(bt->rchild,k); }
三、二叉排序樹的循環算法實現
BSTNode *SearchBST1(BSTNode *bt, KeyType k) { while (bt!=NULL) { if(k==bt->key) return bt; else if(k<bt->key) bt=bt->lchild; else bt=bt->rchild; } return NULL; }
四、二叉排序樹的插入生成。
int InsertBST(BSTNode *&p,KeyType k) { if(p==NULL) { p=(BSTNode *)malloc(sizeof(BSTNode)); p->key=k; p->lchild=p->rchild=NULL; return 1; } else if (k==p->key) return 0; else if (k<p->key) return InsertBST(p->lchild,k); else return InsertBST(p->rchild,k); }
五、二叉排序樹的刪除
int DeleteBST(BSTNode *&bt,KeyType k) { if(bt=NULL) return 0; else { if (k<bt->key) return DeleteBST(bt->lchild,k); else if(k>bt->key) return DeleteBST(bt->rchild,k); else { Delete(bt); return 1; } } } void Delete(BSTNode *&p) { BSTNode *q; if(p->rchild==NULL) { q=p; p=p->lchild; free(q); } else id(p->lchild==NULL) { q=p; p=p->lchild; free(q); } else Delete1(p,p->lchild); } void Delete1(BSTNode *p, BSTNode *&r) { BSTNode *q; if(r-rchild!=NULL) Delete1(p,r->rchild); else { p->key=r->key; q=r; r=r->lchild; free(q); } }
一、排序定義
typedef int KeyType; // 定義關鍵字類型 typedef struct // 記錄類型 { KeyType key; //關鍵字項 InfoType data; // 其餘數據項的類型InfoType }RecType; // 排序的記錄類型定義
二、直接插入排序
void InsertSort(RecType R[],int n) { int i,j; for (i=1,j<n;i++) { tmp=R[i]; j=i-1; while (j>=0&&tmp.key<R[j].key) { R[j+1]=R[j]; j--; } R[j+1]=tmp; } }
三、使用折半查找插入排序
void InsertSort1(RecType R[],int n) { int i,j,low,high,mid; RecType tmp; for(i=1;i<n;i++) { tmp=R[i]; low=0; high=i-1; // 用折半查找肯定插入位置 while (low<=high) { mid=(low+high)/2; if(tmp.key<R[mid].key) high=mid-1; else low=mid+1; } // 順序移動實施插入 for(j=i-1;j>=high+1;j--) R[j+1]=R[j]; R[high+1]=tmp; } }
四、希爾排序
而後取出第二個增量d2(小於d1),重複上述的分組和排序,直至所取增量dt=1(d1>d2>d3..>dt-1>dt),即全部記錄放在同一組中進行直接插入排序爲止。
void ShellSort(RecType R[],int n) { int i,j,gap,k; RecType tmp; gap=n/2; // 增量置初值 while (gap>0) { // 對全部相隔gap位置的全部元素組進行排序 for (i=gap;i<n;i++) { tmp=R[i]; j=i-gap; while (j>=0 && tmp.key<R[j].key) { P[j+gap]=R[j]; j=j-gap; } R[j+gap]=tmp; j=j-gap; } gap=gap/2; //減少增量 } }
五、冒泡排序
void BubbleSort(RecType R[],int n) { int i,j ,k; RecType tmp; for(i=0;i<n-1;i++) { for(j=n-1;j>i;j--) // 一趟冒泡 if(R[j].key < R[j-1].key) { tmp=R[j]; R[j]=R[j-1]; R[j-1]=tmp; } } }
六、快速排序
void QuickSort(RecType R[],int t,int s) { int i=s, j=t; RecType tmp; if(s<t) { tmp=R[s]; //記錄基準 // 進行一次劃分 while(i!=j) { while(j>1&& R[j].key>=tmp.key) j--; R[i]=R[j]; while (i<j && R[i].key<=tmp.key) i++; R[j]=R[i]; } R[i]=tmp; QuickSort(R,s,i-1); QuickSort(R,i+1,t); } }
七、直接選擇排序 插入排序
void SelectSort(RecType R[],int n) { int i,j,k,l; RecType temp; for (i=0;i<n-1;i++) { k=i; // 記錄無序區的起始位置 // 在無序區選擇關鍵字最小的記錄,並記錄下標 for (i=i+1;j<n;j++) if(R[j].key<R[k].key) k=j; // 將關鍵字最小的記錄交換到無序區開始 if(k!=i) { temp=R[i]; Rp[i]=R[k]; R[k]=temp; } } }
八、堆排序
* 堆排序實現原理: - 構造大根堆:從最後一個非葉子節點開始,構造大根堆(雙親節點的值大於其左右孩子節點),若是此節點區域其左右子樹均已成堆,將與「大」分支的根交換,直到成堆。 大者上浮,小者被篩選下去。 - 將構造的大根堆,取出頭節點,此節點爲當前堆的最大值,而後將頭結點和最後的葉子節點交換位置,再次構造大根堆,且最後的葉子節點不參與大根堆得構建,依次循環選出從大到小的值。
// 構造初始堆 void sift(RecType R[],int low,int high) // low 和high 是樹的調整範圍 { int i=low, j=2*i; // R[j] 是R [i] 的左孩子 RecType temp=R[i]; while(j<=high) { if (j<high && R[j].key <R[j+1].key) j++; // 若右孩子較大, j指向右孩 2i+1 if(temp.key<R[j].key) { R[i]=R[j]; // 將R[j]調用到雙親節點位置上 i=j; // 修改i和j的值,以便繼續向下篩選 j=2*i; } else break; // 篩選結束 } R[i]=temp; // 被篩選節點的值放入最終位置 } // 進行堆排序 void HeapSort(RecType R[],int n) { int i; RecType temp; // 循環創建初始堆 for (i=n/2;i>=1; i--) sift(R,i,n); // 選最大值置後並調整堆 for (i=n;i>=2;i--) { temp=R[1]; R[1]=R[i]; R[i]=temp; sift(R,1,i-1); } }
九、歸併排序
* 將兩個或兩個以上的有序表合併成一個新的有序表
void Merge(RecType R[],int low,int mid,int high) { RecType *R1; int i=low, j=mid+1,k=0; /* 動態分配空間R1,用於保存合併結果 */ R1=(RecType *)malloc(high-low+1)*size(RecType)); /** 兩段均未掃描時合併 **/ while (i<=mid && 1<=high) if(R[i].key<=R[j].key) { R1[k]=R[i]; i++; k++; } else { R1[k]=R[j]; j++; k++; } // 將第一段餘下的部分複製到R1 while(i<=mid) { R1[k]=R[i]; i++; k++; } // 將第二段餘下的部分複製到R1 while(j<=high) { R1[k]=R[j]; i++; k++; } // 將合併後的結果複製回R for(k=0,i=low;i<=high;k++,i++) R[i]=R1[k]; } void MergePass(RecType R[],int length,int n) { int i; for (i=0;i+2*length-1<n; i=i+2*length) Merge(R,i,i+length-1,i+2*length-1); if(i+length-1<n) Merge(R,i,i+length-1,n-1); } void MergeSort(RecType R[],int n) { int length; for (length=1;length<n;length=2*length) MergePass(R,length,n); }
一、基數排序的特色:
二、基數排序的存儲結構和算法
#define MAXF 20 //線性表中的最多元素個數 #define MAXR 10 //基數的最大取值 #define MAXD 8 //關鍵字位數的最大取值 //排序數據節點類型 typedef struct node { char data[MAXD]; struct node *next; } RecType1; RecType1 *p; // 用於分配和收集的隊列 RecType1 *head[MAXR],*tail[MAXR] void RadixSort(RecType *&p,int r, int d) { RecType *head[MAXR], *tail[MAXR],*t; int i,j,k; for(i=0;i<=d-1;i++) // 從低位到高位 { // 初始化各鏈隊首和隊尾指針 for(j=0;j<r;j++) head[j]=tail[j]=NULL; //分配每個節點 while(p!=NULL) { k=p->data[i]-'0'; // 將字符裝換爲數字 if(head[k]==NULL) { head[k]=p; tail[k]=p; } else { tail[k]->next=p; tail[k]=p; } p=p->next; } p=NULL; for(j=0;j<r;j++) if(head[j]!=NULL) { if(p==NULL) { p=head[j]; t=tail[j]; } else { t->next=head[j]; t->tail[j]; } } t->next=NULL; }
一、平方階O(n^2)排序,通常稱爲加單排序,如直接插入,直接選擇和冒泡排序。
二、先行對數階O(nlog2n)排序,如快速,堆和歸併排序。
三、線性階O(n)排序,如基數排序。