目录
55.并查集:查找某个集合的根结点(Kruskal算法用到)
线性表
一、顺序存储
1.顺序存储的静态分配
#define MaxSize 50//定义线性表的最大长度
typedef int Elemtype//假定表中元素类型是int
typedef struct{
ElemType data[MaxSize];//顺序表的元素(数组)
int length ;//顺序表的当前长度
2.顺序存储的动态分配
typedef int Elemtype
typedef struct
{
ElemType *data ;//指示动态分配数组的指针
int MaxSize , length ;//数组的最大容量和当前个数
};
/* c语言的动态分配语句 */
#define InitSize 100
SeqList L;
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSzie);
3.顺序存储线性表的插入
bool ListInset(Sqlist &L, int i , ElemType e){
if(i<1 || i>L.length+1) return false ;//判断i的范围是否有效
if(L.length >= MaxSize) return false ;//当前存储空间已满,不能插入
for(int j=L.length ; j>=i ; j--){//将第i个元素及之后的元素后移
L.data[j]=L.data[j-1];
}
L.data[i-1] = e ;//在位置i处放入e
L.length++ ; //线性表长度加1
return true ;
}
4.顺序存储线性表的删除
bool ListDelete(SqList &L , int i ,Elemtype &e){
if(i<1 || i>=L.length) return false;//判断i的范围是否有效
e = L.data[i];//将被删除的元素赋值给e
for(int j=i ; j<=L.length ; j++){//将第i个位置之后的元素前移
L.data[j]=L.data[j+1] ;
}
L.length--; //线性表长度减1
return true ;
}
二、链式存储
5.链式存储线性表的结构
typedef struct LNode //定义单链表结点类型
{
ElemType data ;//数据域
struct LNode *next; //指针域
}LNode, *LinkList;
6.头插法建立单链表
LinkList CreatLinkList(LinkList &L){
LNode *s ; //辅助指针
int x ;
L=(LinkList)malloc(sizeof(LNode)) ; //创建头结点
L->next = NULL ;//初始为空链表
scanf("%d" , &x) ;//输入结点的值
while(x != 9999){//输入9999表示结束
s= (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x ;
s->next = L->next ;
L->next = s ;//将新结点插入表中,L为头指针
scanf("%d" , &x) ;//读入下一个结点值
}
return L;
}
7.尾插法建立单链表
LinkList CreatLinkList(LinkList &L){
int x ;
L=(LinkList)malloc(sizeof(LNode));
LNode *s , *r = L; //r为表尾指针 指向表尾
scanf("%d" , x) ; //输入结点的值
while(x != 9999){//输入9999表示结束
s=(LNode*)malloc(sizeof(LNode)) ;
s->data = x ;
r->next = s ;
r= s ;//r指向新的表尾结点
scanf("%d" , x) ;
}
r->next = NULL ;//尾结点指针置空
return L;
}
8.链式存储按序号查找结点
LNode * GetElem(LInkList L , int i){
int j = 1;//计数,初始为1
LNode *p = L->next ;//第一个结点指针赋给p
if(i==0) return L ;//若i等于0,则返回头结点
if(i<1) return NULL; //若i无效,则返回NULL
while (p && j<i){ //从第1个结点开始找,查找第i个结点
p=p->next ;
j++;
}
return p; //返回第i个结点的指针,如果i大于表长,直接返回p即可
}
9.链式存储按值查找结点
LNode * LocateElem(LinkList L, ElemType e){
LNode *p = L->next;
while(p!=NULL && p->data!=e){//从第1个结点开始查找data域为e的结点
p = p->next ;
}
return p;//找到后返回该结点指针,否则返回NULL
}
10.链式存储插入结点
算法思路: 1.取指向插入位置的前驱结点的指针 ① p=GetElem(L,i-1);
2.令新结点*s的指针域指向*p的后继结点 ② s->next=p->next;
3.令结点*p的指针域指向新插入的结点*s ③ p->next=s;
bool LinkListInsert(LInkList &L , int i ,ElemType e){
if( i<1 || i>=L.length) return false ;
int j = 1;
LNode *p = L->next , *s;
s = (LNode*)malloc(sizeof(LNode));
while (p && j<i-1)
{
p=p->next ;
j++;
}
s->next = p->next;
p->next = s ;
return true ;
}
11.链式存储删除结点
算法思路: 1.取指向删除位置的前驱结点的指针 p=GetElem(L,i-1);
2.取指向删除位置的指针 q=p->next;
3.p指向结点的后继指向被删除结点的后继 p->next=q->next
4.释放删除结点 free(q);
bool LinkListDelete(LInkList &L , int i ,ElemType &e){
if( i<1 || i>=L.length) return false ;
int j = 1;
LNode *p = L->next ,*q ;
while (p && j<i-1)
{
p=p->next ;
j++;
}
q = p->next ;
p->next = q->next;
e = q->data;
free(q) ;
return true ;
}
12.双链表的结构
typedef struct DNode //定义单链表结点类型
{
ElemType data ; //数据域
struct DNode *prior ,*next ;//前驱和后继指针
}DNode ,*DLinkList;
13.双链表的插入
bool DLinListInsert(DLInkList &L , int i ,ElemType e){
if( i<1 || i>=L.length) return false ;
int j = 1;
DNode *p = L->next , *s;
s = (DNode*)malloc(sizeof(DNode));
while (p && j<i-1)
{
p=p->next ;
j++;
}
s->next = p->next;
p->next->prior = s ;
s->prior = p ;
p->next = s;
return true ;
}
14.双链表的删除
bool DLinkListDelete(DLinkList &L , int i ,ElemType &e){
if( i<1 || i>=L.length) return false ;
int j = 1;
DNode *p = L->next ,*q ;
while (p && j<i-1)
{
p=p->next ;
j++;
}
q = p->next ;
p ->next = q->next ;
q ->next->prior = p;
e = q->data;
free(q) ;
return true ;
}
15.静态链表的结构
#define MaxSize 50 //静态链表的最大长度
typedef int ElemType //静态链表的数据类型假定为int
typedef struct //静态链表结构类型的定义
{
ElemType data ; //数据域:存储数据元素
int next ;//指针域:下一个元素的数组下标
}SLinkList[MaxSize];
栈和队列
一、顺序栈
16.栈的结构
#define MaxSize 50 //定义栈中元素的最大个数
typedef struct
{
ElemType data[MaxSize] ;//存放栈中元素
int top ;//栈顶指针
}SqStack; //顺序栈的简写
17.判断栈空
bool StackEmpty(SqStack S){
if(s.top == -1) return true ;
else return false ;
}
18.进栈
bool Push(SqStack &S , ElemType x){
if(S.top == MaxSize-1) return false ;
S.data[++top] = x ;
return true ;
}
19.出栈
bool Pop(SqStack &S,ElemType &x) {
if(S.top == -1) return false ;
x = S.data[top--] ;
return true ;
}
20.读取栈顶元素
bool Pop(SqStack &S,ElemType &x) {
if(S.top == -1) return false ;
x = S.data[top] ;
return true ;
}
21.共享栈的结构
#define MaxSize 100 //定义栈中元素的最大个数
typedef struct
{
ElemType data[MaxSize] ;//存放栈中元素
int top1 ;//栈1栈顶指针
int top2 ;//栈2栈顶指针
}SqDoubleStack; //顺序共享栈的简写
22.共享栈的进栈
bool Push(SqDoubleStack &S , ElemType x , int stackNum){
if(S.top1+1 == S.top2) return false ; //栈满
if(stackNum == 1) //栈1有元素进栈
S.data[++top1] = x;
else(stackNum == 2)//栈2有元素进栈
S.data[--top2] = x;
return true ;
}
二、链式栈
23.链式栈的存储结构
typedef struct SNode
{
ElemType data ;//存放栈中元素
struct SNode *next ; //栈顶指针
}SNode , *SLink; //链栈的结点
typedef struct LinkStack
{
Slink top ; //栈顶指针
int count ; //链栈结点数
}LinkStack; //链栈
24.链式栈的进栈
bool Push(LinkStck &S, ElemType x){
SLink p = (Slink)malloc(sizeof(SNode)) ; //给新元素分配空间
p->data = x ;//新元素的值
p->next = S->top ; //p的后继指向栈顶元素
S->top = p ; //栈顶指针指向新的元素
S->count++ ; //栈中元素个数加1
return true ;
}
25.链式栈的出栈
bool Pop(LinkStack *S , ElemType &x) {
if(S->top == NULL) return false ;
x = S->top->data ; //栈顶元素值
Slink p = S->top ; //辅助指针
S->top = S->top->next ; //栈顶指针后移
free(p); //释放被删除数据的存储空间
S->count-- ;//栈中元素个数减一
return true ;
}
三、顺序队列
26.队列的存储结构
#define MaxSize 50//定义队列中元素的最大个数
typedef struct
{
ElemType data[MaxSize] ;//存放队列元素
int front ,rear ;//队头指针和队尾指针
}SqQueue;
27.队列的入队
bool EnQueue(SqQueue &Q , ElemType x){
if((Q.rear+1)%MaxSize == Q.front ) return false ;//队满
Q.data[Q.rear] = x;
Q.rear = (Q.rear+1)%MaxSize ;
return true ;
}
28.队列的出队
bool DeQueue(SqQueue &Q ,ElemType &x){
if(Q.front == Q.rear) return false ; //队空,报错
x = Q.data[Q.front] ;
Q.front = (Q.front+1)%MaxSize ;
return true ;
}
四、链式队列
29.链式队列的存储结构
typedef struct //链式队列结点
{
ElemType data ;
struct LinkNode *next ;
}LinkNode;
typedef struct //链式队列
{
LinkNode *front,*rear ; //队头和队尾指针
}LinkQueue;
30.链式队列的入队
void EnQueue(LinkQueue &Q, ElemType x){
s=(LinkNode *)malloc(sizeof(LinkNode)) ;
s->data = x ;
s->next = NULL ;
Q.rear->next = s ;
Q.rear = s ;
}
31.链式队列的出队
bool DeQueue(LinkQueue &Q , ElemType &x){
if(Q.rear == Q.front ) return false ; //空队
p = Q.front->next ;
x = p->data ;
Q.front->next = p->next ;
if(Q.rear == p) //若原队列中只有一个结点,删除后变空
Q.rear = Q.front ;
free(p) ;
return true ;
}
五、栈的应用
32.栈的应用:括号匹配
bool Check(char *str){
Stack s ;
InitStck(s) ;
int len = strlen(str) ; //字符串长度为len
for (int i = 0; i<len ; i++)
{
char a = str[i] ;
swith(a){
case '(':
case '[':
case '{'
Push(s,a) ;
break ;
case ')':
if(Pop(s) != '(' ) return false ; //出栈顶。如果不匹配直接返回不合法
break ;
case ']':
if(Pop(s) != '[' ) return false ;
break ;
case '}':
if(Pop(s) != '{' ) return false ;
break ;
}
}
if(Empty(s)) return true ;//匹配完所有括号最后要求栈中为空
else return false ;
}
34.栈的应用:求斐波那契数列的第n项
int Fib(int n){
if( n== 0 ) return 0 ; //1.递归边界 Fib(0)==0, Fib(1)==1
else if(n == 1) return 1 ; //2.递归式 Fib(n)=Fib(n-1)+Fib(n-2)
else return Fib(n-1)+Fib(n-2) ;
}
树和二叉树
一、树的存储结构
35.树的双亲表示法
typedef char ElemType ;
typedef struct TNode
{
ElemType data ; //结点数据
int parent ; //该结点双亲在数组中的下标
}TNode; //结点数据类型
#define MaxSize 100
typedef struct
{
TNode nodes[MaxSize] ; //结点数组
int n; //结点数量
}Tree;//树的双亲表示结构
36.树的孩子表示法
typedef char ElemType ;
typedef struct CNode
{
int chlid ;//该孩子在表头数组的下标
struct CNode *Next ; //指向该结点的下一个孩子结点
}CNode ,*child ;//孩子结点数据类型
typedef struct
{
ElemType data ; //结点数据域
child firstchild ;//指向该结点的第一个孩子结点
}TNode ;//孩子结点数据类型
#define MaxSize 100
typedef struct
{
TNode nodes[MaxSize] ;//结点数据域
int n ;//树中结点个数
}tree; //树的孩子表示结构
37.孩子兄弟表示法
typedef char ElemType ;
typedef struct CSNode
{
ElemType data ;//该结点的数据域
struct CSNode *firstchild ,*rightchild ; //指向该结点的第一个孩子结点和该结点的右兄弟结点
}CSNode ; //孩子兄弟结点数据类型
38.二叉树的链式存储
typedef struct BiTNode
{
ElemType data ;//数据域
struct BiTNode *lchild ,*rchild ; //指向该结点的左、右孩子指针
}BiTNode , *BiTree ; //二叉树结点结构
二、树的遍历
39.二叉树的递归先序遍历
void PreOrder(BiTree T){
if(T != NULL) {
print ("%c" , T->data) ; //访问根结点
PreOrder(T->lchild) ;//递归遍历左子树
PreOrder(T->rchild) ; //递归遍历右子树
}
}
40.二叉树的递归中序遍历
void InOrder(BiTree T){
if(T != NULL){
InOrder(T->lchild) ;//递归遍历左子树
print("%c" , T->data) ;//访问根结点
InOrder(T->rchild) ; //递归遍历右子树
}
}
41.二叉树的递归后序遍历
void PostOrder(BiTree T){
if(T != NULL){
PostOrder(T->lchild) ;//递归遍历左子树
PostOrder(T->rchild) ; //递归遍历右子树
print("%c" , T->data) ;//访问根结点
}
}
42.二叉树的非递归先序遍历
void PreOrderTraverse(BiTree b){
Stack s ;
InitStack(s) ;
BiTree p = b ; //工作指针p
while(p || !IsEmpty){
while(p){
printf("%c", p->data) ; //先序先遍历结点
Push(S,p);
p= p->lchild ;
}
if(!IsEmpty(S)){
p=Pop(s) ;
p= p->rchild ;
}
}
}
43.二叉树的非递归中序遍历
void InOrderTraverse(BiTree b){
Stack s;
InitStack(s) ;
BiTree p = b ; //工作指针p
while (p || !IsEmpty(s)){
while(p){//中序先将结点进栈保存
Push(s,p) ;
p = p->lchild ;
}
//遍历到左下角尽头再出栈访问
p = Pop(s) ;
printf("%c" , p->data) ;
p = p->rchild ;//遍历右孩子
}
}
44.二叉树的非递归后序遍历
void PostOrderTraverse(BiTree T){
InitStack(S) ;
BiTree p = b , r = NULL ;//工作指针p 辅助指针r
while(p || !IsEmpty(s)){
//1.从根结点到最左下角的左子树都入栈
if(p){
Push(S,p) ;
p=p->lchild ;
}
//2.返回栈顶的两种情况
else{
GetTop(S,p) ;//取栈顶注意不是出栈!
//①右子树还未访问,而且右子树不空,第一次栈顶
if(p->rchild && p->rchild!=r)
p = p->rchild ;
//②右子树已经访问或为空,接下来出栈访问结点
else{
Pop(S,p);
printf("%c" , p->data) ;
r = p ; //指向访问过的右子树根结点
p = NULL ;//使p为空从而继续访问栈顶
}
}
}
}
45.二叉树的层序遍历
void LevelOrder(BiTree T){
InitQueue(Q) ;
BiTree p ;
EnQueue(Q , b) ; //根结点进队
while (!IsEmpty(Q))//队列不空循环
{
DeQueue(Q , p); //队头元素出队
printf("%c" , p->data) ;
if(p->lchild != NULL)
EnQueue(Q,p->lchild) ;
if(p->rchild != NULL)
EnQueue(Q,p->rchild) ;
}
}
三、线索二叉树
46.线索二叉树的结构
typedef struct ThreadNode
{
ElemType data ;
struct ThreadNode *lchild , *rchild ;
int ltag ,rtag ;
}ThreadNode ,*ThredTree;//线索链表
47.中序遍历对二叉树线索化的递归算法
void InThread(ThreadTree &p ,ThreadTree &pre){
if(p){//pre指向中序遍历时上一个刚刚访问过的结点 初值为NUL
InThread(p->lchild , pre) ;
if(p->lchild == NULL){
p->lchild = pre ;
p->ltag = 1 ;
}
if(pre!=NULL && pre->rchild==NULL){
pre->rchild = p ;
p->rtag = 1 ;
}
pre = p ;
InThread(p->rchild,pre) ;
}
}
48.遍历线索二叉树
void InOrderTraverse(ThreadTree T){
ThredTree p = T ;
while(p){
while(p->ltag == 0){
p = p->lchild ;
printf("%c", p->data) ;
}
while(p->rtag==1 && p->rchild){
p=p->rchild ;
printf("%c", p->data) ;
}
p = p->rchild ;
}
}
图
一、图的存储结构
49.图的邻接矩阵存储
#define MaxVertexNum 100//顶点数目的最大值
typedef char VertexType ;//顶点的数据类型 不同情况不一样
typedef int EdgeType ;//整数表示权值或者连通性
typedef struct
{
VertexType Vex[MaxVertexNum];//顶点表
EdgeType Edge[MaxVertexNum][MaxVertexNum] ;//邻接矩阵(二维数组),边表
int vexnum , arcnum ;//图的当前顶点数和弧数
}MGraph;
50.图的邻接表存储
typedef struct VNode//顶点表结点
{
VertexType data ;//顶点信息
ArcNode *firstedge ;//单链表头指针
}VNode,AdjList[MaxVertexNum];//AdjList是结构体数组类型
#define MaxVertexNum 100//图中顶点数目的最大值
typedef struct ArcNode//边表结点
{
int adjvex ;//该弧所指向的顶点的位置
struct ArcNode *next ;//指向下一条弧的指针
}ArcNode;
typedef struct
{
AdjList vertices ;//邻接表
int vexnum ,arcnum ;//图的顶点数和弧数
}ALGraph;//ALGraph是以邻接表存储的图类型
二、图的遍历
51.图的广度优先搜索遍历(BFS)
#define MaxSize 100
bool visited[MaxSize] ;
void BFS(Graph G ,int v){
ArcNode *p ;//工作指针p
InitQueue(Q) ;//初始化一个队列
visited(v) ;//访问第一个顶点v,具体可以是print
visited[v] = TRUE ;//对v做已访问标记
while(!IsEmpty(Q)){//只要队列不为空
DeQueue(Q,v) ;//顶点v出队列
p = G->adjList[v].firstedge ;//指针p指向当前顶点的边表链表头指针
while(p){
if(!visited[p->adjvex]){//p指向顶点如果未被访问
visited(p->adjvex) ;//访问p所指向的顶点
visited[p->adjvex] = TRUE ;//对这个顶点做已访问标记
EnQueue(Q, p->adjvex) ;//这个顶点入队列
}
p=p->next ;//p指向该顶点的下一条边
}
}
}
void BFSTraverse(Graph G){
int i ;//单独定义是为了方便多个循环中使用
for (i=0;i<G->vexnum ; i++){
visited[i] = false ;//将标志数组初始化(全局数组)
}
for (i=0;i<G->vexnum ; i++){
if(!visited[i]) BFS(G,i);//为了避免非连通图的一些顶点访问不到,若是连通图只会执行一次
}
}
52.BFS应用:单源非带权图最短路径
void BFS_MIN_Distance(Graph G, int u){
for(i=0;i<G.vexnum;++i) d[i] = ∞ ;//d[i]表示从u到i结点的最短路径
visited[u] = TRUE ;
d[u] = 0 ;
EnQueue(Q,u) ;
while(!IsEmpty(Q)){
DeQueue(Q,u) ;
ArcNode *p = G->adjList[u].firstedge;
while(p){
if(!visited[p->adjvex]){
visited[p->adjvex] = TRUE ;
d[p->adjvex] = d[u]+1 ;//路径长度加1
EnQueue(Q,p->adjvex) ;
}
p=p->next;
}
}
}
53.图的深度优先遍历(DFS)
#define MaxSize 100
bool visited[MaxSize] ;
void DFS(Graph G, int v){
ArcNode *p ;//工作指针p
visit(v);//访问顶底v(一般是打印,printf)
visited[v] = TRUE ;//修改访问标记
p = G->adjList[v].firstarc;//指针p开始指向该顶点的第一条边
while(p!=NULL){//没遍历完顶点的所有邻接顶点
if(!visited[p->adjvex]){//如果该顶点没被访问
DFS(G,p->adjvex);//递归访问该顶点
}
p=p->nextarc ;//看还有没有其他未访问的顶点
}
}
void DFSTraverse(Graph G){
int i ;//单独定义是为了方便多个循环中使用
for (i=0;i<G->vexnum ; i++){
visited[i] = false ;//将标志数组初始化 (全局数组)
}
for (i=0;i<G->vexnum ; i++){
if(!visited[i]) DFS(G,i);//对所有
}
}
三、图的最小生成树
54.求图的最小生成树(Prim算法)
void MiniSpanTree_Prim(MGraph G){
int min ,i ,j ,k ;
int adjvex[MAXVEX] ;//保存邻接顶点下标的数组
int lowcost[MAXVEX] ;//记录当前生成树到剩余顶点的最小权值
lowcost[0] = 0 ;//将0号顶点(以0号顶点作为第一个顶点)加入生成树
adjvex[0] = 0 ;//由于刚开始生成树只有一个顶点 不存在边 干脆都设为0
for(i=0 ;i<G.vexnum ;i++){//除下标为0以外的所有顶点
lowcost[i] = G.arc[0][i];//将与下标为0的顶点有边的权值存入Lowcost数组
adjvex[i] = 0 ;//这些顶点的adjvex数组全部初始化为0
}
for(i=1;i<G.vexnum;i++){//只需要循环N-1次,N为顶点数
min = 65535 ;//tip:因为要找最小值,不妨先设取一个最大的值来比较
j = 0 ;
k = 0 ;
//找出lowcost最小的 最小权值给min,下标给k
while(j<G.vexnum){//从1号顶点开始找
if(lowcost[j]!=0 && lowcost<min){//不在生成树中的顶点而且权值更小的
min = lowcost[j] ;//更新更小的值
k = j ;//找到了新的点下标给k
}
j++ ;//再看下一个顶点
}
printf("(%d->%d)",adjvex[k],k;//打印权值最小的边
lowcost[k] = 0 ;//将这个顶点加入生成树
//生成树加入了新的顶点 从下标为1的顶点开始更新lowcost数组值
for(j=0;j<G.vexnum;j++){
if(lowcost[j]!= && G.arc[k][j]<lowcost[j]){//如果新加入树的顶点k使得权值变小
lowcost[j] = G.arc[k][j] ;//更新更小的权值
adjvex[j] = k ;//修改这条边邻接的顶点 也就是表示这条边是从选出的顶点k指过来的 方便打印
}
}
}
}
55.并查集:查找某个集合的根结点(Kruskal算法用到)
int Find(int *parent, int x){
while (parent[x]>=0) x=parent[x];//循环寻找x的根
return x ;//根的parent小于0
}
56.并查集:合并两个集合(Kruskal算法用到)
void Union(inbt *parent,int root1 ,int root2){
parent[root2] = root1 ;
}
57.求图的最小生成树:(Kruskal算法)克鲁斯卡尔
#define 100
typedef struct
{
int a,b ;//边的两个顶点
int weight ;//边的权值
}Edge;//边的结构体
int Find(int *parent, int x){
while (parent[x]>=0) x=parent[x];//循环向上寻找下表为x顶点的根
return x ;//while循环结束时找到了根的下标
}
Edge edges[MaxEdge] ;//边数组
int parent[MaxVex] ;//父亲顶点数组(并查集)
void MiniSpanTree_Kruskal(MGraph G){
int i,n,m ;
sort(edges) ;//按权值由小到大对边排列
for (int i=0;i<G.vexnum;i++){
parent[i] = -1 ;//初始化:各个顶点单独形成一个集合
}
for(i=0;i<arcnum;i++){//扫描每条边
n = Find(parent,edges[i].a) ;//n是这条边的第一个顶点的根顶点所在下标
m = Find(parent,edges[i].b) ;//m是这条边第二个顶点的根顶点所在下标
if(n!=m){//根顶点不相同 这条边不会构成环
parent[n] = m ;//并操作
printf("(%d->%d)",edges[i].a,edges[i].b);//作为生成树的一条边打印出来
}
}
}
四、图的最短路径
58.图的最短路径算法(Dijkstra算法)迪杰斯特拉
void Dijkstra(MGraph G,int v,int path[],int dist[]){ //v是源点的下标
int s[maxSize]; //数组s记录当前找到了到哪些顶点的最短路径 找到了对应值为1 没找的对应值为0
int i,j,min,u;
//初始化 将path dist s 数组的初值确定
for(i=0 ; i<G.vexnum ; i++){
dist[i]=G.edge[v][i]; //dist初值为源点到各个顶点的边的权值
s[i]=0; //一开始没有一个顶点
if(G.edge[v][i]<65535)path[i]=v; //与源点连通的顶点的path值存源点下标
else path[i]=-1;//刚开始到源点没有路径的顶点path值为-1
}
s[v]=1; //源点加入集合s
path[v]=-1; //源点不存在到自身的路径
//下面的循环中包含两部分作用:
①内层第一个for循环是找到 到剩余顶点中距离最小的 顶点u 并把它加入最短路径
②内层第二个for循环是由新加入的顶点u来判断是否找到了新的更短路径,如果有就更新没有就不做任何操作
for(i=0;i<G.vexnum;i++){
min=65535;
for(j=0;j<G.vexnum;j++){
if(s[j]==0&&dist[j]<min){ //从剩余的顶点中找到距离最小的顶点
u=j;//u用于保存当前找到的距离最小的顶点下标 当循环结束u保存的就是最小距离的顶点下标
min=dist[j];
}
}
s[u]=1;//到u的距离是最小的,所以把顶点u加入最短路径
for(j=0;j<G.vexnum;j++){
if(s[j]==0 && dist[u]+G.Edges[u][j]<dist[j]){
dist[j]=dist[u]+G.Edges[u][i];//如果由新加入最短路径的顶点u到其他剩余顶点的距离变短了则修改到剩余顶点的距离为较小值
path[j]=u;//这条较短的路径是由顶点u过来的
}
}
}
}
59.图的最短路径算法(Floyd算法)弗洛伊德
void Floyd(MGraph G,int Path[][]){
int i, j, k ;
int A[MaxSize][MaxSize];
//对数组A[][]和Path[][]进行初始化
for(i=0; i<G.vexnums; i++){
for(j=0; j<G.vexnums; j++){
A[i][j]=G.Edges[i][j];
Path[i][j]=-1;
}
}
for(k=0; k<G.vexnums; k++){
for(i=0; i<G.vexnums; i++){
for(j=0; j<G.vexnums; j++){
if(A[i][j]>A[i][k]+A[k][j]){//如果顶点i到顶点j的距离比顶点i经过顶点k到顶点j的距离长,则更新从顶点i到顶点j的距离为较小值,并且存储k表示路径经过顶点k
A[i][j]=A[i][k]+A[k][j];
Path[i][j]=k;
}
}
}
}
}
查找
60.折半查找
int Binary_Search(SeqList L,ElemType key,int n){//L是一个顺序表,key是待查找的关键字,n是L的长度
int low=0,high=n-1,mid;//low high mid 分别代表当前查找段的首位下标,末位下标和中间下标
while(low<=high){//只要low不和hig汇合,就表示查找表没有扫描完
mid=(low+high)/2;//中间下标为low和high之和除2
if(L.elem[mid]==key)//查找成功
return mid;
else if(L.elem[mid]>key)//中间值比key大
high=mid-1; //由于有序,则key只可能在更小的地方出现
else//中间值比key小
low=mid+1; //key只可能在更小的地方出现
}
return -1;
}
61.二叉排序树查找关键字(递归)
BiTNode *BST_Search(BiTNode *t,ElemType key){
if(t==NULL)return NULL; //如果树为空则 返回空值
else{
if(t->key==key) return t;
else if(key<t->key) return BST_Search(t->lchild,key);
else return BST_Search(t->rchild,key);
}
62.二叉排序树查找关键字(非递归)
BiTNode * BST_Search(BiTNode *t,ElemType key){
BiTNode *p=t;//工作指针 初值指向二叉排序树根结点
while(p!=NULL && key!=p->data){//p不为空且没有找到key
if(key<p->data) p=p->lchild;//如果key值比p指向结点值小,则查找左子树
else p=p->rchild;//如果key值比p指向结点值大,则查找右子树
}
return p;//查找成功返回指向值为key值的结点的指针 查找失败返回NULL
}
63.二叉排序树插入关键字
int BST_Insert(BiTNode* &t,ElemType k){ //插入操作是要对树进行修改,所以是引用类型的指针
if(t==NULL){//原树为空,新插入的记录为根结点
t=(BiTNode*)malloc(sizeof(BiTNode));//malloc库函数分配新结点的存储空间
t->key=k;//该结点的关键字值赋值为k
t->lchild=t->rhild=NULL;//根结点初始化左右孩子为空
return 1;//返回1,表示成功
}
else if(k==t->key)//树中存在相同关键字的结点 插入失败
return 0;
else if(k<t->key)//插入到t的左子树中
return BST_Insert(t->lchild,k);
else//插入到t的右子树中
return BST_Insert(t->rchild,k);
}
64.二叉排序树构造代码
void Creat_BST(BiTNode *&t,ElemType key[ ],int n){
//t是二叉排序树的根结点指针 key是关键字数组 n是关键字数量
t=NULL; //初始时t为空树
int i=0;
while(i<n){
BST_Insert(t,key[i]);
i++;
}
}
排序
65.直接插入排序
void InsertSort(ElemType A[],int n){
int i,j;
for(i=2;i<=n;i++){
if(A[i].key<A[i-1].key){
A[0]=A[i];//复制为哨兵,A[0]不存放元素
for(j=i-1;A[0].key<A[j].key;--j)
A[j+1]=A[j];//所有比待插入元素值大的都往后移一位,腾出空位
A[j+1]=A[0];//复制到插入位置
}
}
}
66.希尔排序
void ShellSort (ElemType A[],int n){
int i,j;
for(dk=n/2;dk>=1;dk=dk/2){//初始增量为总长度的一半,之后依次除2且向下取整,且最后一次要为1
for(i=dk+1;i<=n;++i){
if(A[i].key<A[i-dk].key){//A[i].key是待插入的关键字,i-dk之前的都是有序的,如果待插入的比有序序列最后一个小, 则需要进行排序(进入if语句块),如果大则不需要(跳出if语句块)
A[0]=A[i]; //待插入关键字暂存在A[0]
for(j=i-dk;j>0&&A[0].key<A[j].key; j-=dk)//待插入关键字之前以dk为增量的关键字只要比待插入关键字大的都往后移动dk位
A[j+dk]=A[j];
A[j+dk]=A[0]; //找到了待插入的位置,就将待插入关键字插入这个位置
}
}
}
}
67.冒泡排序
void BubbleSort(ElemType A[],int n){
for(i=0;i<n-1;i++){
bool flag=false; //tips:当整个序列都有序的时候,标志位是不发生修改的,从而表示已经排好了
for(j=n-1;j>i;j--) //一趟冒泡过程
if(A[j-1].key>A[j].key){ //如果前面的元素比后面的大,则需要做交换
ElemType temp=A[j-1].key;
A[j-1].key=A[j].key;
A[j].key=temp;
flag=true; //发生了数据交换修改标志位
}
if(flag==false)return ; //本趟遍历后没有发生交换,说明表已经有序
}
}
68.快速排序
int Partition(ElemType A[],int low,int high){//low是当前待排序的序列起始下标,high是末尾下标
ElemType pivot=A[low];//第一个元素作为枢轴
while(low<high){
while(low<high&&A[high]>=pivot) --high;//先从末尾往前找到第一个比枢轴小的元素
A[low]=A[high];//用high的元素替换low的元素
while(low<high&&A[low]<=pivot) ++low; //再从开头往后找到第一个比枢轴大的元素
A[high]=A[low];//用low的元素替换high的元素
}
A[low]=pivot;//枢轴元素存放到最终位置
return low; //返回存放枢轴的最终位置
}
void QuickSort(ElemType A[],int low,int high){
if(low<high){//low和high值要合法
int pivotpos=Partition(A,low,high);
QuickSort(A,low,pivotpos-1);//分治递归左半部分
QuickSort(A,pivotpos+1,high);//分治递归右半部分
}
}
69.选择排序
void SelectSort(ElemType A[],int n){
for(i=0;i<n-1;i++){//依次从后面序列中选择当前最小的元素作为第i个元素 最后一个元素不需要排序
min=i;//min存的是当前最小元素所在下标,初值设为第i个
for(j=i+1;j<n;j++)//从第i个元素往后找,一直要找到最后一个元素
if(A[j]<A[min]) min=j;//如果这个值更小,则更新min值为这个更小的元素所在下标
if(min!=i){//如果第i个元素不是剩下元素最小的,则和最小的进行交换
ElemType temp=A[i];
A[i]=A[min];
A[min]=temp;
}
}
}
70.堆排序
void BuildMaxHeap(ElemType A[],int len){
for(int i=len/2;i>0;i--) AdjustDown(A,i,len);
}
void AdjustDown(ElemType A[],int k,int len){
A[0]=A[k];
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]<A[i+1])i++;
if(A[0]>=A[i]) break;
else{
A[k]=A[i];
k=i;
}
}
A[k]=A[0];
}
void HeapSort(ElemType A[],int len){
BuildMaxHeap(A,len);//初始建堆
for(i=len;i>1;i--){//n-1趟的交换和建堆过程
//输出堆顶元素(和堆底元素交换)
ElemType temp=A[i];
A[i]=A[1];
A[1]=temp;
printf(A[i]);
AdjustDown(A,1,i-1);//把剩余的i-1个元素整理成堆
}
}
71.归并排序
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //辅助数组B(动态分配内存)
void Merge(ElemType A[],int low,int mid,int high){
//表A的两段A[low…mid]和A[mid+1…high]各自有序,将它们合并成一个有序表
for(int k=low;k<=high;k++) B[k]=A[k];//将A中所有元素复制到B中
for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){ //k是归并之后数组的下标计数器
if(B[i]<=B[j])//比较B的左右两段中的元素
A[k]=B[i++];//将较小值复制到A中
else
A[k]=B[j++];
}
while(i<=mid) A[k++]=B[i++];//若第一个表未检测完,直接将剩下的部分复制过来
while(j<=high) A[k++]=B[j++];//若第二个表未检测完,直接将剩下的部分复制过来
}
void MergeSort(ElemType A[],int low,int high){
if(low<high){
int mid=(low+high)/2;//从中间划分两个子序列
MergeSort(A,low,mid);//对左侧子序列进行递归排序
MergeSort(A,mid+1,high);//对右侧子序列进行递归排序
Merge(A,low,mid,high);//归并
}
}
73.拓扑排序
bool TopologicalSort(Graph G){
InitStack(S);//初始化栈,存储入度为0的顶点
for(int i=0;i<G.vexnum;i++)
if(indegree[i]==0)Push(S,i);//将所有入度为0的顶点进栈
int count=0;//计数,记录当前已经输出的顶点数
while(!IsEmpty(S)){//栈不空,则存在入度为0的顶点
Pop(S,i);//栈顶元素出栈
pritnf(“%d”,G.adjlist[i]);
for(ArcNode *p=G.vertices[i].firstarc; p; p=p->nextarc){
v=p->adjvex; //取这条弧指向的顶点
if(!(--indegree[v]))Push(S,v);//入度减1为0,则入栈
}
}
if(count<G.vexnum)return false;//排序失败,有向图中有回路
else return true; //拓扑排序成功
}