最小生成树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#define MAXE 100
#define MAXV 100
typedef struct{
int vex1; //边的起始顶点
int vex2; //边的终止顶点
int weight; //边的权值
}Edge;
void kruskal(Edge E[],int n,int e)
{
int i,j,m1,m2,sn1,sn2,k,sum=0;
int vset[n+1];
for(i=1;i<=n;i++) //初始化辅助数组
vset[i]=i;
k=1;//表示当前构造最小生成树的第k条边,初值为1
j=0;//E中边的下标,初值为0
while(k<e)//生成的边数小于e时继续循环
{
m1=E[j].vex1;
m2=E[j].vex2;//取一条边的两个邻接点
sn1=vset[m1];
sn2=vset[m2];
//分别得到两个顶点所属的集合编号
if(sn1!=sn2)//两顶点分属于不同的集合,该边是最小生成树的一条边
{//防止出现闭合回路
printf("V%d-V%d=%d\n",m1,m2,E[j].weight);
sum+=E[j].weight;
k++; //生成边数增加
if(k>=n)//没有边或者找到的边>顶点数减1都退出循环
break;
for(i=1;i<=n;i++) //两个集合统一编号
if (vset[i]==sn2) //集合编号为sn2的改为sn1
vset[i]=sn1;
}
j++; //无论上一条边是否被收入最下生成树,都要扫描下一条边
//k++与j++的位置不同,k++在循环内部(只有满足条件才能被收入最小生成树),j++在循环外部
}
printf("the lowest weight=%d\n",sum);
}
void swap(Edge arr[],int low,int high)
{
Edge temp;
temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;

}
int fun(Edge arr[],int low,int high)
{
int key;
Edge lowx;
lowx=arr[low];
key=arr[low].weight;
while(low<high)
{
while(low<high && arr[high].weight>=key)
high--;
if(low<high)
swap(arr,low,high);
//arr[low++]=arr[high];

while(low<high && arr[low].weight<=key)
low++;
if(low<high)
swap(arr,low,high);
//arr[high--]=arr[low];
}
arr[low]=lowx;
return low;
}
void quick_sort(Edge arr[],int start,int end)
{
int pos;
if(start<end)
{
pos=fun(arr,start,end);
quick_sort(arr,start,pos-1);
quick_sort(arr,pos+1,end);
}
}
void gen(Edge E[],int vertex,int edge)
{
for(int i=0;i<edge;i++)
scanf("%d%d%d",&E[i].vex1,&E[i].vex2,&E[i].weight);
}
int main()
{
Edge E[MAXE];
int vertex,edge;
//freopen("1.txt","r",stdin);//文件输入
printf("please intput the vertexs and edges:\n");
scanf("%d%d",&vertex,&edge);
gen(E,vertex,edge);
quick_sort(E,0,edge-1);
kruskal(E,vertex,edge);
}

Prim算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*
prim朴素实现
reference: http://www.slyar.com/blog/prim-simplicity-c.html
*/
#include <stdio.h>

#define MAX 100
#define INF 0x3f3f3f3f

int graph[MAX][MAX];

int Prim(int graph[][MAX], int n)
{
int lowcost[MAX], mst[MAX];
/*
lowcost[i]记录以i为终点的边的最小权值,当lowcost[i]=0时表示终点i加入生成树
mst[i]记录对应lowcost[i]的起点,当mst[i]=0时表示起点i加入生成树
*/
int i, j, min, minid, sum = 0;

for (i = 2; i <= n; i++) //默认选择1号节点加入生成树,从2号节点开始初始化
{
lowcost[i] = graph[1][i]; //最短距离初始化为其他节点到1号节点的距离
mst[i] = 1; //标记所有节点的起点皆为默认的1号节点
}

mst[1] = 0; //标记1号节点加入生成树

for (i = 2; i <= n; i++) //n个节点至少需要n-1条边构成最小生成树
{
min = INF;
minid = 0;

for (j = 2; j <= n; j++) //找满足条件的最小权值边的节点minid
{
if (lowcost[j] < min && lowcost[j] != 0) //边权值较小且不在生成树中
{
min = lowcost[j];
minid = j;
}
}
printf("%c - %c : %d\n", mst[minid] + 'A' - 1, minid + 'A' - 1, min); //输出生成树边的信息:起点,终点,权值

sum += min; //累加权值
lowcost[minid] = 0; //标记节点minid加入生成树

for (j = 2; j <= n; j++) //更新当前节点minid到其他节点的权值
{
if (graph[minid][j] < lowcost[j]) ///发现更小的权值
{
lowcost[j] = graph[minid][j]; //更新权值信息
mst[j] = minid; //更新最小权值边的起点
}
}
}
return sum; //返回最小权值和
}

int main()
{
int m, n, weight;
char chx, chy;

scanf("%d %d", &m, &n); //读取节点和边的数目
getchar();
for (int i = 1; i <= m; i++) //初始化图,所有节点间距离为无穷大
for (int j = 1; j <= m; j++)
graph[i][j] = INF;
for (int k = 0; k < n; k++) //读取边信息
{
scanf("%c %c %d", &chx, &chy, &weight);
getchar();
int i = chx - 'A' + 1, j = chy - 'A' + 1; ///ABCDEF
graph[i][j] = weight;
graph[j][i] = weight;
}

printf("Total: %d\n", Prim(graph, m));

return 0;
}

顺序表

KMP算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void getNext(char pattern[],int next[]){
next[0]=-1;
int i=0,j=-1;
int pat_leng = strlen(pattern);
while(i<pat_leng){
if(j==-1) {
i++;
j++;
} else if(pattern[i] == pattern[j]){
i++;j++;
next[i]=j;
} else{
j=next[j];
}
}
}

二叉树

二叉树的周游

前序遍历

1
2
3
4
5
6
7
8
9
10
11
12
//二叉树前序遍历递归算法
void PreOrderTraverse(BiTree T)
{
if(T == NULL)
{
return;
}
printf("%C",T->data); //显示结点数据
PreOrderTraverse(T->lchild); //先序遍历左子树
PreOrderTraverse(T->rchild);//最后先序遍历右子树

}

中序遍历

1
2
3
4
5
6
7
8
9
10
11
12
//二叉树中序遍历递归算法
void InOrderTraverse(BiTree T)
{
if(T == NULL)
{
return;
}
InOrderTraverse(T->lchild); //中序遍历左子树
printf("%C",T->data); //显示结点数据
PreOrderTraverse(T->rchild);//最后中序遍历右子树

}

后序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
//二叉树后序遍历递归算法
void PostOrderTraverse(BiTree T)
{
if(T == NULL)
{
return;
}

PreOrderTraverse(T->lchild); //后续序遍历左子树
PreOrderTraverse(T->rchild);//后序遍历右子树
printf("%C",T->data); //显示结点数据

}

层序遍历

使用bfs算法即可

排序算法的应用

使用归并排序求逆序对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <stdio.h>

int merge(int arr[], int temp[], int left, int mid, int right)
{
int i, j, k;
int count = 0;
i = left; // 左半部分的数组起始位置
j = mid + 1; // 右半部分的数组起始位置
k = left; // 临时数组的起始位置

while (i <= mid && j <= right) // 当左右两边都有数时
{
if (arr[i] <= arr[j]) // 如果左边的数小于等于右边的数
{
temp[k++] = arr[i++]; // 把左边的数放入临时数组中
}
else // 如果右边的数小于左边的数
{
temp[k++] = arr[j++]; // 把右边的数放入临时数组中
count += (mid - i + 1); // 左边数组剩余的数都大于右边的数,累加逆序对数量
}
}

// 当左边或右边有剩余时,将它们依次放入临时数组中
while (i <= mid)
{
temp[k++] = arr[i++];
}
while (j <= right)
{
temp[k++] = arr[j++];
}

// 将临时数组中的元素复制回原数组中
for (i = left; i <= right; i++)
{
arr[i] = temp[i];
}

return count;
}

int mergeSort(int arr[], int temp[], int left, int right)
{

if (left < right) // 当数组长度大于1时,继续分割
{
int count = 0;
int mid = (left + right) / 2;
count += mergeSort(arr, temp, left, mid); // 左半部分数组的逆序对数量
count += mergeSort(arr, temp, mid + 1, right); // 右半部分数组的逆序对数量
count += merge(arr, temp, left, mid, right); // 合并左右两部分数组,并统计逆序对数量
return count;
}
return 0;
}

int main()
{
int arr[] = {2, 4, 3, 1, 5, 6 };
int n = sizeof(arr) / sizeof(int);
int temp[n]; // 临时数组
int count = mergeSort(arr, temp, 0, n - 1); // 统计逆序对数量
printf("逆序对数量: %d\n", count);

int arr1[] = {20, 23, 11, 5, 21, 56};
int n1 = sizeof(arr1) / sizeof(int);
int temp1[n1]; // 临时数组
int count1 = mergeSort(arr1, temp1, 0, n1 - 1); // 统计逆序对数量
printf("逆序对数量: %d\n", count1);
}