一、非空二叉树上的叶节点数等于双分支节点数加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)排序,如基数排序。