学习任务补记

学习中…………

                                                             (知识和深度会不断增加,我会经常更新 ……  (0 · 0) )

2011-7-18:

基础数据结构——栈、队列

2011-7-19:

二叉排序树代码,弄完栈和队列的同学可以看一下——指针实现

2011-7-20:

  快速排序+归并排序

Merge.cpp
1 void Merge( DataType a[], int n, DataType swap[], int k )
2 {
3 int m = 0, u1, u2, i, j, l2;
4 int l1 = 0;
5
6 while ( l1 + k <= n -1 )
7 {
8 l2 = l1 + k;
9 u1 = u2 - 1;
10 u2 = ( l2 + k - 1 <= n - 1)? l2 + k - 1: n - 1;
11
12 //两个有序子数组的合并
13 for ( i = l1, j = l2; i <= u1 && j <= u2; m ++ )
14 {
15 if ( a[i].key <= a[j].key )
16 {
17 swap[a] = a[i];
18 i ++;
19 }
20 else
21 {
22 swap[m] = a[j];
23 j ++;
24 }
25 }
26
27 //子数组2已归并完,将子数组1中剩余元素存放到数组swap中
28 while ( i <= u1 )
29 {
30 swap[m] = a[i];
31 m ++;
32 i ++;
33 }
34
35 //子数组1已归并完,将子数组2中剩余元素存放到数组swap中
36 while( j <= u2 )
37 {
38 swap[m] = a[j];
39 m ++;
40 j ++
41 }
42
43 l1 = u2 + 1;
44 }
45
46 //将原始数组中只够一组的数据元素顺序存放到数组swap中
47 for ( i = l1; i < n; i ++, m ++)
48 {
49 swap[m] = a[i];
50 }
51 }
MergeSort.cpp
 1 void MergeSort( DataType a[], int n )
2 {
3 int i, k = 1;
4 DataType *swap = new DataType[n];
5
6 while ( k < n )
7 {
8 Merge(a, n, swap, k);
9 for (i = 0; i < n; i ++)
10 {
11 a[i] = swap[i];
12 }
13
14 k = 2 * k
15 }
16
17 delete []swap;
18 }

2011-7-21:

高精度计算

View Code
#include <iostream>
#include
<string>
using namespace std;

inline
int compare(string str1, string str2)
{
if(str1.size() > str2.size()) //长度长的整数大于长度小的整数
return 1;
else if(str1.size() < str2.size())
return -1;
else
return str1.compare(str2); //若长度相等,从头到尾按位比较,compare函数:相等返回0,大于返回1,小于返回-1
}
//高精度加法
string ADD_INT(string str1, string str2)
{
string MINUS_INT(string str1, string str2);
int sign = 1; //sign 为符号位
string str;
if(str1[0] == '-') {
if(str2[0] == '-') {
sign
= -1;
str
= ADD_INT(str1.erase(0, 1), str2.erase(0, 1));
}
else {
str
= MINUS_INT(str2, str1.erase(0, 1));
}
}
else {
if(str2[0] == '-')
str
= MINUS_INT(str1, str2.erase(0, 1));
else {
//把两个整数对齐,短整数前面加0补齐
string::size_type l1, l2;
int i;
l1
= str1.size(); l2 = str2.size();
if(l1 < l2) {
for(i = 1; i <= l2 - l1; i++)
str1
= "0" + str1;
}
else {
for(i = 1; i <= l1 - l2; i++)
str2
= "0" + str2;
}
int int1 = 0, int2 = 0; //int2 记录进位
for(i = str1.size() - 1; i >= 0; i--) {
int1
= (int(str1[i]) - 48 + int(str2[i]) - 48 + int2) % 10; //48 为 '0' 的ASCII 码
int2 = (int(str1[i]) - 48 + int(str2[i]) - 48 +int2) / 10;
str
= char(int1 + 48) + str;
}
if(int2 != 0) str = char(int2 + 48) + str;
}
}
//运算后处理符号位
if((sign == -1) && (str[0] != '0'))
str
= "-" + str;
return str;
}


//高精度减法
string MINUS_INT(string str1, string str2)
{
string MULTIPLY_INT(string str1, string str2);
int sign = 1; //sign 为符号位
string str;
if(str2[0] == '-')
str
= ADD_INT(str1, str2.erase(0, 1));
else {
int res = compare(str1, str2);
if(res == 0) return "0";
if(res < 0) {
sign
= -1;
string temp = str1;
str1
= str2;
str2
= temp;
}
string::size_type tempint;
tempint
= str1.size() - str2.size();
for(int i = str2.size() - 1; i >= 0; i--) {
if(str1[i + tempint] < str2[i]) {
str1[i
+ tempint - 1] = char(int(str1[i + tempint - 1]) - 1);
str
= char(str1[i + tempint] - str2[i] + 58) + str;
}
else
str
= char(str1[i + tempint] - str2[i] + 48) + str;
}
for(i = tempint - 1; i >= 0; i--)
str
= str1[i] + str;
}
//去除结果中多余的前导0
str.erase(0, str.find_first_not_of('0'));
if(str.empty()) str = "0";
if((sign == -1) && (str[0] != '0'))
str
= "-" + str;
return str;
}

//高精度乘法
string MULTIPLY_INT(string str1, string str2)
{
int sign = 1; //sign 为符号位
string str;
if(str1[0] == '-') {
sign
*= -1;
str1
= str1.erase(0, 1);
}
if(str2[0] == '-') {
sign
*= -1;
str2
= str2.erase(0, 1);
}
int i, j;
string::size_type l1, l2;
l1
= str1.size(); l2 = str2.size();
for(i = l2 - 1; i >= 0; i --) { //实现手工乘法
string tempstr;
int int1 = 0, int2 = 0, int3 = int(str2[i]) - 48;
if(int3 != 0) {
for(j = 1; j <= (int)(l2 - 1 - i); j++)
tempstr
= "0" + tempstr;
for(j = l1 - 1; j >= 0; j--) {
int1
= (int3 * (int(str1[j]) - 48) + int2) % 10;
int2
= (int3 * (int(str1[j]) - 48) + int2) / 10;
tempstr
= char(int1 + 48) + tempstr;
}
if(int2 != 0) tempstr = char(int2 + 48) + tempstr;
}
str
= ADD_INT(str, tempstr);
}
//去除结果中的前导0
str.erase(0, str.find_first_not_of('0'));
if(str.empty()) str = "0";
if((sign == -1) && (str[0] != '0'))
str
= "-" + str;
return str;
}
//高精度除法
string DIVIDE_INT(string str1, string str2, int flag)
{
//flag = 1时,返回商; flag = 0时,返回余数
string quotient, residue; //定义商和余数
int sign1 = 1, sign2 = 1;
if(str2 == "0") { //判断除数是否为0
quotient = "ERROR!";
residue
= "ERROR!";
if(flag == 1) return quotient;
else return residue;
}
if(str1 == "0") { //判断被除数是否为0
quotient = "0";
residue
= "0";
}
if(str1[0] == '-') {
str1
= str1.erase(0, 1);
sign1
*= -1;
sign2
= -1;
}
if(str2[0] == '-') {
str2
= str2.erase(0, 1);
sign1
*= -1;
}
int res = compare(str1, str2);
if(res < 0) {
quotient
= "0";
residue
= str1;
}
else if(res == 0) {
quotient
= "1";
residue
= "0";
}
else {
string::size_type l1, l2;
l1
= str1.size(); l2 = str2.size();
string tempstr;
tempstr.append(str1,
0, l2 - 1);
//模拟手工除法
for(int i = l2 - 1; i < l1; i++) {
tempstr
= tempstr + str1[i];
for(char ch = '9'; ch >= '0'; ch --) { //试商
string str;
str
= str + ch;
if(compare(MULTIPLY_INT(str2, str), tempstr) <= 0) {
quotient
= quotient + ch;
tempstr
= MINUS_INT(tempstr, MULTIPLY_INT(str2, str));
break;
}
}
}
residue
= tempstr;
}
//去除结果中的前导0
quotient.erase(0, quotient.find_first_not_of('0'));
if(quotient.empty()) quotient = "0";
if((sign1 == -1) && (quotient[0] != '0'))
quotient
= "-" + quotient;
if((sign2 == -1) && (residue[0] != '0'))
residue
= "-" + residue;
if(flag == 1) return quotient;
else return residue;
}

//高精度除法,返回商
string DIV_INT(string str1, string str2)
{
return DIVIDE_INT(str1, str2, 1);
}
//高精度除法,返回余数
string MOD_INT(string str1, string str2)
{
return DIVIDE_INT(str1, str2, 0);
}
int main()
{
char ch;
string s1, s2, res;
while(cin >> ch) {
cin
>> s1 >> s2;
switch(ch) {
case '+': res = ADD_INT(s1, s2); break; //高精度加法
case '-': res = MINUS_INT(s1, s2); break; //高精度减法
case '*': res = MULTIPLY_INT(s1, s2); break; //高精度乘法
case '/': res = DIV_INT(s1, s2); break; //高精度除法, 返回商
case 'm': res = MOD_INT(s1, s2); break; //高精度除法, 返回余数
default : break;
}
cout
<< res << endl;
}
return(0);
}

2011-7-22:

贪心算法

堆排序代码 

有个牛人讲的很好可以直接去他那看:http://www.wutianqi.com/?p=1820

View Code
 // array是待调整的堆数组,i是待调整的数组元素的位置,length是数组的长度
void HeapAdjust(int array[], int i, int nLength)
{
int nChild, nTemp;

for (nTemp = array[i]; 2 * i + 1 < nLength; i = nChild)
{
// 子结点的位置是 父结点位置 * 2 + 1
nChild = 2 * i + 1;
// 得到子结点中较大的结点
if (nChild != nLength - 1 && array[nChild + 1] > array[nChild])
++nChild;
// 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
if (nTemp < array[nChild])
{
array[i]
= array[nChild];
}
else // 否则退出循环
{
break;
}
}
// 最后把需要调整的元素值放到合适的位置
array[i] = nTemp;
}

// 堆排序算法
void HeapSort(int array[], int length)
{
// 调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素
for (int i = length / 2 - 1; i >= 0; --i)
{
HeapAdjust(array, i, length);
}
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for (int i = length - 1; i > 0; --i)
{
// 把第一个元素和当前的最后一个元素交换,
// 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的
Swap(&array[0], &array[i]);
// 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
HeapAdjust(array, 0, i);
}
}

2011-7-23:

哈希表

方法
哈希表的设计主要是设计哈希函数

哈希函数:将关键字映射到哈希表的位置

哈希函数的建立有五种常见方法:

1. 除余法

2.折叠法

3.平方取中法

4.提取法

5. 基数转换法

哈希冲突解决方法

1. 开放定址法

开放定址法又分为线性探查法,二次探查法,双散列函数探查法

2.再哈希法

3.链地址法

4.建立一个公共溢出区

可扩展文件的散列函数

1.可扩展散列

2.线性散列



哈希程序示例:

冲突解决方法为:双散列函数探查法

哈希函数关键字为:人名字母ASCII相加

哈希函数为:关键字
%M,从而映射到哈希表中的位置
代码
#include<stdio.h>
#include
<conio.h>
#define HASH_LEN 50 //哈希表的长度
#define M 47 //随机数
#define NAME_NO 30 //人名的个数
typedef
struct

{
char *py; //名字的拼音
int k; //拼音所对应的整数
}NAME;

NAME NameList[HASH_LEN];
//全局变量NAME

typedef
struct //哈希表
{
char *py; //名字的拼音
int k; //拼音所对应的整数
int si; //查找长度
}HASH;

HASH HashList[HASH_LEN];
//全局变量HASH

void InitNameList() //姓名(结构体数组)初始化
{

char *f;
int r,s0,i;
NameList[
0].py="wanghui";
NameList[
1].py="mayuelong";
NameList[
2].py="chenzhicheng";
NameList[
3].py="sunpeng";
NameList[
4].py="zengqinghui";
NameList[
5].py="liqingbo";
NameList[
6].py="liujunpeng";
NameList[
7].py="jiangquanlei";
NameList[
8].py="xingzhengchuan";
NameList[
9].py="luzhaoqian";
NameList[
10].py="gaowenhu";
NameList[
11].py="zhuhaoyin";
NameList[
12].py="chenlili";
NameList[
13].py="wuyunyun";
NameList[
14].py="huangjuanxia";
NameList[
15].py="wangyan";
NameList[
16].py="zhoutao";
NameList[
17].py="jiangzhenyu";
NameList[
18].py="liuxiaolong";
NameList[
19].py="wangziming";
NameList[
20].py="fengjunbo";
NameList[
21].py="lilei"
NameList[
22].py="wangjia";
NameList[
23].py="zhangjianguo";
NameList[
24].py="zhuqingqing";
NameList[
25].py="huangmin";
NameList[
26].py="haoyuhan";
NameList[
27].py="zhoutao";
NameList[
28].py="zhujiang";
NameList[
29].py="lixiaojun";
for (i=0;i<NAME_NO;i++)
{
s0
=0;
f
=NameList[i].py;
for (r=0;*(f+r)!='\0';r++)
s0
=*(f+r)+s0;
NameList[i].k
=s0;

}
}

void CreateHashList() //建立哈希表

{
int i;
for (i=0; i<HASH_LEN;i++)
{
HashList[i].py
="";
HashList[i].k
=0;
HashList[i].si
=0;
}

for (i=0;i<HASH_LEN;i++)
{
int sum=0;
int adr=(NameList[i].k)%M; //哈希函数
int d=adr;
if(HashList[adr].si==0) //如果不冲突
{
HashList[adr].k
=NameList[i].k;
HashList[adr].py
=NameList[i].py;
HashList[adr].si
=1;
}
else //冲突
{
do
{
d
=(d+NameList[i].k%10+1)%M; //伪随机探测再散列法处理冲突
sum=sum+1; //查找次数加1
}while (HashList[d].k!=0);
HashList[d].k
=NameList[i].k;
HashList[d].py
=NameList[i].py;
HashList[d].si
=sum+1;
}
}
}

void FindList() //查找
{
char name[20]={0};
int s0=0,r,sum=1,adr,d;
printf(
"\n请输入姓名的拼音:");
scanf(
"%s",name);
for (r=0;r<20;r++) //求出姓名的拼音所对应的整数(关键字)
s0+=name[r];
adr
=s0%M; //使用哈希函数
d=adr;
if(HashList[adr].k==s0) //分3种情况进行判断
printf("\n姓名:%s 关键字:%d 查找长度为: 1",HashList[d].py,s0);
else if (HashList[adr].k==0)
printf(
"无此记录!");
else
{
int g=0;
do
{
d
=(d+s0%10+1)%M; //伪随机探测再散列法处理冲突
sum=sum+1;
if (HashList[d].k==0)
{
printf(
"无此记录! ");
g
=1;
}
if (HashList[d].k==s0)
{
printf(
"\n姓名:%s 关键字:%d 查找长度为:%d",HashList[d].py,s0,sum);
g
=1;
}

}
while(g==0);

}
}

void Display() // 显示哈希表
{
int i;
float average=0;
printf(
"\n\n地址\t关键字\t\t搜索长度\tH(key)\t 姓名\n"); //显示的格式
for(i=0; i<50; i++)
{
printf(
"%d ",i);
printf(
"\t%d ",HashList[i].k);
printf(
"\t\t%d ",HashList[i].si);
printf(
"\t\t%d ",HashList[i].k%M);
printf(
"\t %s ",HashList[i].py);
printf(
"\n");
}
for (i=0;i<HASH_LEN;i++)
average
+=HashList[i].si;
average
/=NAME_NO;
printf(
"\n\n平均查找长度:ASL(%d)=%f \n\n",NAME_NO,average);

}


void main()

{
char ch1;
printf(
"\n 哈希表的建立和查找\n");
printf(
" *-------------------------------------------*\n");
printf(
" | D. 显示哈希表 |\n");
printf(
" | F. 查找 |\n");
printf(
" | Q. 退出 |\n");
printf(
" *-------------------------------------------*\n");
InitNameList();
CreateHashList ();

while(1)
{
printf(
"\n Option-:");
fflush(stdin);
ch1
=getchar();
if (ch1=='D'||ch1=='d')
Display();
else if (ch1=='F'||ch1=='f')
FindList();
else if (ch1=='Q'||ch1=='q')
return;
else
{
printf(
"\n请输入正确的选择!");
}
}
}

2011-7-24:

休息

2011-7-25:

并查集

View Code
#include <stdio.h>
#include
<stdlib.h>
#include
<string.h>
struct road
{
int st;
int ed;
int w;
};
road all[
900];
int A[30];
int cmp(const void *a,const void *b)
{
return (*(road *)a).w - (*(road *)b).w;
}
int find(int x)
{
if (x != A[x])
A[x]
= find(A[x]);
return A[x];
}
int main()
{
int i,j,k,q,p,m,n,sum;
char s,e;
while (scanf("%d",&n) != EOF)
{
if (n == 0) break;
memset(A,
0,sizeof(int));
for (i = 1;i <= n;i++)
A[i]
= i;
m
= 0;
for (i = 1;i < n;i++)
{
scanf(
" %c%d",&s,&p);
while (p--)
{
scanf(
" %c%d",&e,&q);
all[m].st
= s - 'A';
all[m].ed
= e - 'A';
all[m].w
= q;
m
++;
}
}
qsort(all,m,
sizeof(all[0]),cmp);
k
= 0;sum = 0;
while (k < m)
{
all[k].st
= find(all[k].st);
all[k].ed
= find(all[k].ed);
if (all[k].st != all[k].ed)
{
sum
+= all[k].w;
A[all[k].st]
= all[k].ed;
}
k
++;
}
printf(
"%d\n",sum);
}
system(
"pause");
return 0;
}
View Code
//【模板】并查集模板(经典应用——最小生成树)

//根采用数字本身和使用递归实现

int father[MAX]; //father[x]表示x的父节点
int num[MAX]; //num[x]表示x的秩,即x所在集合的元素个数

//初始化集合
void Make_Set(int x)
{
father[x]
= x; //根据实际情况指定的父节点可变化
num[x] = 1; //根据实际情况初始化秩也有所变化
}

//查找x元素所在的集合,回溯时压缩路径
int Find_Set(int x)
{
if (x != father[x])
{
father[x]
= Find_Set(father[x]); //回溯时的压缩路径
}//从x结点搜索到祖先结点所经过的结点都指向该祖先结点
return father[x];
}

//按秩合并x,y所在的集合,按秩合并,实时更新秩。
void Union(int a, int b)
{
int x = Find_Set(a);
int y = Find_Set(b);
if(x == y)
{
return;
}
if(num[x] <= num[y])
{
father[x]
= y;
num[y]
+= num[x];
}
else
{
father[y]
= x;
num[x]
+= num[y];
}
}




//采用-1做根和使用非递归实现

void Make_Set(int n)
{
for(i = 0; i < n; i++)
{
father[i]
= -1;
num[i]
= 1;
}
}

//非递归实现,没有路径压缩
int Find_Set(int x)
{
while(father[x] != -1) //根为-1
{
x
= father[x];
}
return x;
}

2011-7-26:

Trie树

基本实现
#include<algorithm>
#include
<iostream>
using namespace std;

const int sonnum=26,base='a';
struct Trie
{
int num;//to remember how many word can reach here,that is to say,prefix
bool terminal;//If terminal==true ,the current point has no following point
struct Trie *son[sonnum];//the following point
};
Trie
*NewTrie()// create a new node
{
Trie
*temp=new Trie;
temp
->num=1;temp->terminal=false;
for(int i=0;i<sonnum;++i)temp->son[i]=NULL;
return temp;
}
void Insert(Trie *pnt,char *s,int len)// insert a new word to Trie tree
{
Trie
*temp=pnt;
for(int i=0;i<len;++i)
{
if(temp->son[s[i]-base]==NULL)temp->son[s[i]-base]=NewTrie();
else temp->son[s[i]-base]->num++;
temp
=temp->son[s[i]-base];
}
temp
->terminal=true;
}
void Delete(Trie *pnt)// delete the whole tree
{
if(pnt!=NULL)
{
for(int i=0;i<sonnum;++i)if(pnt->son[i]!=NULL)Delete(pnt->son[i]);
delete pnt;
pnt
=NULL;
}
}
Trie
* Find(Trie *pnt,char *s,int len)//trie to find the current word
{
Trie
*temp=pnt;
for(int i=0;i<len;++i)
if(temp->son[s[i]-base]!=NULL)temp=temp->son[s[i]-base];
else return NULL;
return temp;
}
another
//字典树模板
#include <iostream>
using namespace std;
const int kind=26;
struct node
{
int i,count;
node
*next[kind];
node()
{
count
=1;
for(i=0;i<kind;i++)
next[i]
=NULL;
}
};
void insert(node *root,char *word)
{
int i=0,branch;
node
*local=root;
if(local==NULL)
{
local
=new node();
root
=local;
}
while(word[i])
{
branch
=word[i]-'a';
if(local->next[branch])
local
->next[branch]->count++;
else
local
->next[branch]=new node();
i
++;
local
=local->next[branch];
}
}
int search(node *root,char *word)
{
int i=0,branch,ans;
node
*local=root;

if(local==NULL)
return 0;
while(word[i])
{
branch
=word[i]-'a';
if(!local->next[branch])
return 0;
i
++;
local
=local->next[branch];
ans
=local->count;
}
return ans;
}
int main()
{
char str[12];
node
*root=new node;
while(gets(str) && strcmp(str,""))
insert(root,str);
while(scanf("%s",str)!=EOF)
printf(
"%d\n",search(root,str));
return 0;
}

相关知识:自动机(hdu 2222,附代码见下面)(矩阵快速幂、容斥原理,KMP)

自己写的太乱,还是放个思路比较清晰的吧
#include <iostream>
using namespace std;
const int size = 26;
struct node
{
int count;
node
*son[size];
node
*fail;
node()
{
count
= 0;
fail
= NULL;
for (int i = 0; i < size; i ++){
son[i]
= NULL;
}
}
}
*q[10000];


void insert(char *a, node *root)//建立字典树
{
int len =strlen(a);
node
*p = root;
for (int i = 0; i < len; i ++){
int k = a[i] - 'a';
if (p -> son[k] == NULL){
p
-> son[k] = new node;
}
p
= p -> son[k];
}
p
-> count ++;
}


void build_ac_automation(node *root)//建立AC自动机
{
int head = 0, tail = 0;
root
->fail = NULL;
q[tail
++] = root;

while (head != tail){
node
*temp = q[head ++];
node
*p = NULL;
for (int i = 0; i < 26; i ++){
if (temp -> son[i] != NULL){//如果字母('a'+i)存在于单词中
if (temp == root){
temp
-> son[i] -> fail = root;//如果为根结点,则fail指向root
}
else {//如果不存在,则依次取当前字母(temp)和其父节点字母(p)
p = temp -> fail;
while (p != NULL){//当前字母的父节点存在
if (p -> son[i] != NULL){//遍历看其父节点中有无同样的字母'a'+i
temp -> son[i] -> fail = p -> son[i];//如果有,则改变当前temp的fail指针使其指向父节点的('a'+i)字母
break;
}
p
= p -> fail;//继续向上探询父节点
}
if (p == NULL)temp -> son[i] -> fail = root; //如果遍历到最上层都没有找到则将fail指向root
}
q[tail
++] = temp -> son[i];//当前点继续入队实现BFS;
}

}
}
}


int find(node *root, char *a)
{
int ans = 0, len = strlen(a);
node
*p = root;
for (int i = 0; i < len; i ++){
int k = a[i] - 'a';
//如果当前字母没有匹配项则匹配其下一个fail指向的字母,如果都没有则回到根结点
while (p -> son[k] == NULL && p != root)p = p -> fail;
//匹配当前字母
p = p -> son[k];
//如果当前没有字母,则回到根节点
p = (p == NULL)? root : p;
node
*temp = p;
//如果当前存在字母(但是不知道是否相同)且没有被匹配过,则查找能够匹配的字母个数
while (temp != root && temp -> count != -1){
ans
+= temp -> count;
temp
-> count = -1;
temp
= temp -> fail;
}
}
return ans;
}
char word[51], word1[1000010];
int main()
{

int t, n;
scanf(
"%d", &n);
while (n --){
scanf(
"%d", &t);
node
*root;
root
= new node;
while (t --){
scanf(
"%s", word);
insert(word, root);
}
build_ac_automation(root);
scanf(
"%s", word1);
printf(
"%d\n", find(root, word1));
}
return 0;
}

2011-7-27:

图的深度遍历

BFS+DFS
#include<stdio.h>
#include
<stdlib.h>
#define Max 10
#define FALSE 0
#define TRUE 1
#define Error printf
#define QueueSize 30

typedef
struct
{
char vexs[Max];
int edges[Max][Max];
int n,e;
}MGraph;

int visited[Max];

typedef
struct
{
int front;
int rear;
int count;
int data[QueueSize];
}CirQueue;

//初始化队列
void InitQueue(CirQueue *Q)
{
Q
->front=Q->rear=0;
Q
->count=0;
}

//队列空
int QueueEmpty(CirQueue *Q)
{
return Q->count=QueueSize;
}

//队列满
int QueueFull(CirQueue *Q)
{
return Q->count==QueueSize;
}

//进队
void EnQueue(CirQueue *Q,int x)
{
if(QueueFull(Q))
{
Error(
"Queue overflow");
}
else
{
Q
->count++;
Q
->data[Q->rear]=x;
Q
->rear=(Q->rear+1)%QueueSize;
}
}

//出队
int DeQueue(CirQueue *Q)
{
int temp;
if(QueueEmpty(Q))
{
Error(
"Queue underflow");
}
else
{
temp
=Q->data[Q->front];
Q
->count--;
Q
->front=(Q->front+1)%QueueSize;
return temp;
}
}

//建立图矩阵
void CreateMGraph(MGraph *G)
{
int i,j,k;
char ch1,ch2;
printf(
"\n\t\t请输入顶点数,边数并按回车键(格式:3,4):");
scanf(
"%d,%d",&(G->n),&(G->e));
for(i=0;i<G->n;i++)
{
getchar();
printf(
"\n\t\t请输入第%d个顶点序号并按回车键",i+1);
scanf(
"%c",&(G->vexs[i]));
}
for(i=0;i<G->n;i++)
{
for(j=0;j<G->n;j++)
{
G
->edges[i][j]=0;
}
}
for(k=0;k<G->e;k++)
{
getchar();
printf(
"\n\t\t请输入第%d条边的顶点序号并按回车键(格式:i,j):",k+1);
scanf(
"%c,%c",&ch1,&ch2);
for(i=0;ch1!=G->vexs[i];i++);
for(j=0;ch2!=G->vexs[j];j++);
G
->edges[i][j]=1;
}
}

//深度优先遍历递归
void DFSM(MGraph *G,int i)
{
int j;
printf(
"\n\t\t深度遍历序列:%c\n",G->vexs[i]);
visited[i]
=TRUE;
for(j=0;j<G->n;j++)
{
if(G->edges[i][j]==1&&!visited[j])
{
DFSM(G,j);
}
}
}

//广度优先遍历递归
void BFSM(MGraph *G,int k)
{
int i,j;
CirQueue Q;
InitQueue(
&Q);
printf(
"\n\t\t广度优先遍历序列:%c\n",G->vexs[k]);
visited[k]
=TRUE;
EnQueue(
&Q,k);
while(!QueueEmpty(&Q))
{
i
=DeQueue(&Q);
for(j=0;j<G->n;j++)
{
if(G->edges[i][j]==1 &&! visited[j])
{
visited[j]
=TRUE;
EnQueue(
&Q,j);
}
}
}
}

//深度优先遍历
void DFSTraverseM(MGraph *G)
{
int i;
for(i=0;i<G->n;i++)
{
visited[i]
=FALSE;
}
for(i=0;i<G->n;i++)
{
if(!visited[i])
{
DFSM(G,i);
}
}
}

//广度优先遍历
void BFSTraverseM(MGraph *G)
{
int i;
for(i=0;i<G->n;i++)
{
visited[i]
=FALSE;
}
for(i=0;i<G->n;i++)
{
if(!visited[i])
{
BFSM(G,i);
}
}
}

main()
{
MGraph
*G,a;
char ch1;
int i,j,ch2;
G
=&a;
printf(
"\n\t\t建立一个图矩阵\n");
CreateMGraph(G);
printf(
"\n\t\t已建立图的矩阵\n");
for(i=0;i<G->n;i++)
{
printf(
"\n\t\t ");
for(j=0;j<G->n;j++)
{
printf(
"%5d",G->edges[i][j]);
}
}
getchar();
ch1
='y';
while(ch1=='y'||ch1=='Y')
{
printf(
"\n");
printf(
"\n\t\t 图子系统 \n");
printf(
"\n\t\t***************************************\n");
printf(
"\n\t\t* 1--------更新矩阵 *\n");
printf(
"\n\t\t* 2--------深度优先遍历 *\n");
printf(
"\n\t\t* 3--------广度优先遍历 *\n");
printf(
"\n\t\t* 0--------退出 *\n");
printf(
"\n\t\t***************************************\n");
printf(
"\n\t\t请选择菜单号(0~3):");
scanf(
"%d",&ch2);
getchar();
switch(ch2)
{
case 1:
CreateMGraph(G);
printf(
"\n\t\t图建立完毕!\n");
break;
case 2:
DFSTraverseM(G);
break;
case 3:
BFSTraverseM(G);
break;
case 0:
ch1
='n';
break;
default:
system(
"cls");
printf(
"\n\t\t输入有误!\n");
break;
}
if(ch2==1||ch2==2||ch2==3)
{
printf(
"\n\n\t\t ");
system(
"pause");
system(
"cls");
}
}
}

2011-7-28:

休息

最小生成树

介绍
(1) 克鲁斯卡尔算法
图的存贮结构采用边集数组,且权值相等的边在数组中排列次序可以是任意的.该方法对于边相对比较多的不是很实用,浪费时间.
(
2) 普里姆算法
图的存贮结构采用邻接矩阵.此方法是按各个顶点连通的步骤进行,需要用一个顶点集合,开始为空集,以后将以连通的顶点陆续加入到集合中,全部顶点加入集合后就得到所需的最小生成树 .
具体介绍:http:
//www.wutianqi.com/?p=1284
prim代码
#include <stdio.h>
//#include <limits.h>
#define INT_MAX 0x7fffffff
#define N 100

int p[N], key[N], tb[N][N];

void prim(int v, int n)
{
int i, j;
int min;

for (i = 1; i <= n; i++)
{
p[i]
= v;
key[i]
= tb[v][i];
}
key[v]
= 0;
for (i = 2; i <= n; i++)
{
min
= INT_MAX;
for (j = 1; j <= n; j++)
if (key[j] > 0 && key[j] < min)
{
v
= j;
min
= key[j];
}
printf(
"%d%d ", p[v], v);
key[v]
= 0;
for (j = 1; j <= n; j++)
if (tb[v][j] < key[j])
p[j]
= v, key[j] = tb[v][j];
}
}

int main()
{
int n, m;
int i, j;
int u, v, w;
while (scanf("%d%d", &n, &m))
{
for(i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
tb[i][j]
= INT_MAX;
}

while (m--)
{
scanf(
"%d%d%d", &u, &v, &w);
tb[u][v]
= tb[v][u] = w;
}
prim(
1, n);
printf(
"\n");
}
return 0;
}


其他算法可以去下面的连接,讲的很好:

最短路径算法---Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
最短路径算法—Bellman-Ford(贝尔曼-福特)算法分析与实现(C/C++)
最短路径算法—SPFA(Shortest Path Faster Algorithm)算法分析与实现(C/C++)

2011-7-29:

拓扑排序

暂时没找到很好的
//拓扑排序的模板
#include <iostream>
using namespace std;

struct data
{
int in; // 某点的入度
int out; // 某点的出度
}s[];

int a,b,n,stk[];
bool visited[];
bool map[][];

int calc()
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(map[i][j])
{
s[i].
out++;
s[j].
in++;
}
}
}

for(i=0;i<n;i++)
if( s[i].in + s[i].out != n-1 )
return 0;

return 1;
}

void push(int k);
{
stk[
++top] = k;
}


void toplogical_sort()
{
int i,j;
bool flg = 1;
int zerop;
for(i=1;i<=n;i++)
{
if(!s[i].in)
{
zerop
= i;
break;
}
}
memset(visited,
false,sizeof(visited));
while(flg)
{
flg
= 0;
for(i=1;i<=n;i++)
{
if ( !visited[i] )
{
if (map[zerop][i])
{
s[i].
in--;
}
if ( s[i].in == 0 )
{
zerop
= i;
flg
= 1;
}
}
}
}
}

void Output() //输出拓扑排序的结果
{
int i;
for(i=1;i<=top;i++)
cout
<< stk[i] << " ";
cout
<< endl;
}

int main()
{
memset(map,
0,sizeof(map));
memset(s,
0,sizeof(s));
for(i=1;i<=n;i++)
{
cin
>> a >> b;
s[a].
out++;
s[b].
in++;
map[a][b]
= 1;
}
top
= 0;
calc();
toplogical_sort();
Output();

return 0;
}

2011-7-30:

字符串匹配(KMP)

好像有点问题,大体思路对
#include<stdio.h>
#include
<string.h>
#include
<stdlib.h>
FILE
*fin=fopen("test.in","r");
FILE
*fout=fopen("test.out","w");
char s1[200],s2[200];
int next[200];

int max(int a,int b)
{
if(a>b) return a;
return b;
}

void getnext()
{
memset(next,
0,sizeof(next));
int i=-1,j=0;
next[
0]=-1;
while(j<strlen(s2))
{
if(i==-1||s2[i]==s2[j])
{
i
++;j++;
next[j]
=i;
}
else i=next[i];
}
}

int KMP()
{
int i=0,j=0,len1=strlen(s1),len2=strlen(s2);
while((i<len1)&&(j<len2))
{
if(j==-1||s1[i]==s2[j]) {j++;i++;}
else j=next[j];
}
if(j==len2) return i-len2;
else return -1;
}

int index_KMP()
{
int i=0,j=0,len1=strlen(s1),len2=strlen(s2),re=0;
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j]) {i++;j++;}
else j=next[j];
re
=max(re,j);
}
return re;
}

int main()
{
fscanf(fin,
"%s",s1);
for(int i=1;i<=3;i++)
{
fscanf(fin,
"%s",s2);
getnext();
fprintf(fout,
"%d %d\n",KMP(),index_KMP());
}
return 0;
}

2011-7-31:

休息

补加资料:

1、AC自动机算法详解(转载:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见
的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树
(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。如果你对
KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干什么用的。KMP中我们用两个指针i和j分别表示
,A[i
-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串
的前 j个字符,当A[i
+1]≠B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配,
而next函数恰恰记录了这个j应该调整到的位置。同样AC自动机的失败指针具有同样的功能,也就是说当我们的模式串在Tire上进行匹配时
,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。看下面这个例子:给定5个单
词:say she shr he her,然后给定一个字符串yasherhs。问一共有多少单词在这个字符串中出现过。我们先规定一下AC自动机所需要的
一些数据结构,方便接下去的编程。
代码1
 1 const int kind = 26; 
2 struct node{
3 node *fail; //失败指针
4 node *next[kind]; //Tire每个节点的个子节点(最多个字母)
5 int count; //是否为该单词的最后一个节点
6 node(){ //构造函数初始化
7 fail=NULL;
8 count=0;
9 memset(next,NULL,sizeof(next));
10 }
11 }*q[500001]; //队列,方便用于bfs构造失败指针
12 char keyword[51]; //输入的单词
13 char str[1000001]; //模式串
14 int head,tail; //队列的头尾指针

有了这些数据结构之后,就可以开始编程了:
   
首先,将这5个单词构造成一棵Tire,如图-1所示。

代码2
 1 void insert(char *str,node *root){ 
2 node *p=root;
3 int i=0,index;
4 while(str[i]){
5 index=str[i]-'a';
6 if(p->next[index]==NULL) p->next[index]=new node();
7 p=p->next[index];
8 i++;
9 }
10 p->count++; //在单词的最后一个节点count+1,代表一个单词
11 }

在构造完这棵Tire之后,接下去的工作就是构造下失败指针。构造失败指针的过程概括起来就一句话:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。具体操作起来只需要:先把root加入队列(root的失败指针指向自己或者NULL),这以后我们每处理一个点,就把它的所有儿子加入队列,队列为空。

代码3
 1 void build_ac_automation(node *root){
2 int i;
3 root->fail=NULL;
4 q[head++]=root;
5 while(head!=tail){
6 node *temp=q[tail++];
7 node *p=NULL;
8 for(i=0;i<26;i++){
9 if(temp->next[i]!=NULL){
10 if(temp==root) temp->next[i]->fail=root;
11 else{
12 p=temp->fail;
13 while(p!=NULL){
14 if(p->next[i]!=NULL){
15 temp->next[i]->fail=p->next[i];
16 break;
17 }
18 p=p->fail;
19 }
20 if(p==NULL) temp->next[i]->fail=root;
21 }
22 q[head++]=temp->next[i];
23 }
24 }
25 }
26 }

从代码观察下构造失败指针的流程:对照图-2来看,首先rootfail指针指向NULL,然后root入队,进入循环。第1次循环的时候,我们需要处理2个节点:root->next[‘h’-‘a’](节点h) root->next[‘s’-‘a’](节点s)。把这2个节点的失败指针指向root,并且先后进入队列,失败指针的指向对应图-2中的(1)(2)两条虚线;第2次进入循环后,从队列中先弹出h,接下来p指向h节点的fail指针指向的节点,也就是root;进入第13行的循环后,p=p->fail也就是p=NULL,这时退出循环,并把节点efail指针指向root,对应图-2中的(3),然后节点e进入队列;第3次循环时,弹出的第一个节点a的操作与上一步操作的节点e相同,把afail指针指向root,对应图-2中的(4),并入队;第4次进入循环时,弹出节点h(图中左边那个),这时操作略有不同。在程序运行到14行时,由于p->next[i]!=NULL(rooth这个儿子节点,图中右边那个),这样便把左边那个h节点的失败指针指向右边那个root的儿子节点h,对应图-2中的(5),然后h入队。以此类推:在循环结束后,所有的失败指针就是图-2中的这种形式。


最后,我们便可以在AC自动机上查找模式串中出现过哪些单词了。匹配过程分两种情况:(1)当前字符匹配, 表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;(2)当前字符 不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。
代码4
1 int query(node *root){ 
2 int i=0,cnt=0,index,len=strlen(str);
3 node *p=root;
4 while(str[i]){
5 index=str[i]-'a';
6 while(p->next[index]==NULL && p!=root) p=p->fail;
7 p=p->next[index];
8 p=(p==NULL)?root:p;
9 node *temp=p;
10 while(temp!=root && temp->count!=-1){
11 cnt+=temp->count;
12 temp->count=-1;
13 temp=temp->fail;
14 }
15 i++;
16 }
17 return cnt;
18 }

对照图-2,看一下模式匹配这个详细的流程,其中模式串为yasherhs。对于i=0,1。Trie中没有对应的路径,故不做任何操作;i=2,3,4 时,指针p走到左下节点e。因为节点e的count信息为1,所以cnt+1,并且讲节点e的count值设置为-1,表示改单词已经出现过了,防止重复 计数,最后temp指向e节点的失败指针所指向的节点继续查找,以此类推,最后temp指向root,退出while循环,这个过程中count增加了 2。表示找到了2个单词she和he。当i=5时,程序进入第5行,p指向其失败指针的节点,也就是右边那个e节点,随后在第6行指向r节点,r节点的 count值为1,从而count+1,循环直到temp指向root为止。最后i=6,7时,找不到任何匹配,匹配过程结束。

    到此为止AC自动机算法的详细过程已经全部介绍结束,看一道例题:http://acm.hdu.edu.cn/showproblem.php?pid=2222(就是上面在讲trie的时候,相关知识里的一个题)

posted @ 2011-08-01 01:56  Soul_ice  阅读(219)  评论(0)    收藏  举报