C
语言与算法设计技能培训
1
、用C语言实现下列各种排序:冒泡排序、选择排序、快速排序冒泡排序函数如下:
/*n表示待排序的数据的个数*/
#define
n 10
void
maopao(int a[])
{int i,j,temp;
for(i=0;i<n-1;++i)
{
for( j=0;j<n-i;++j)
if(a[j]>a[j+1])
{temp=a[j];a[j]=a[j+1];a[j+1]=temp;}
}
}
/*选择排序*/
void xuanze(int a[n])
{int i,j,temp,k;
for(i=0;i<n-1;++i)
{k=i;
for(j=i+1;j<n;++j)
if(a[k]<a[j])
k=j;
if(k!=i){temp=a[i];a[i]=a[k];a[k]=temp;}
}
}
/*快速排序*/
int part(int a[n],int low,int high)
{int x;
x=a[low];
while(low<high)
{
while(low<high&&a[high]>=x)
--high;
a[low]=a[high];
while(low<high&&a[low]<=x)
++low;
a[high]=a[low];
}
a[low]=x;
return low;
}
void Qsort(int a[n],int low,int high)
{int pivotloc;
if(low<high)
{ pivotloc=part(a,low,high);
Qsort(a,low,pivotloc-1);
Qsort(a,pivotloc+1,high);
}
}
main()
{
int a[n],j;
for(j=0;j<n;++j)
scanf("%d",&a[j]);
maopao(a);for(j=0;j<n;++j)
printf("%5d",a[j]);
printf("/n");
for(j=0;j<n;++j)
scanf("%d",&a[j]);
xuanze(a);for(j=0;j<n;++j)
printf("%5d",a[j]);printf("/n");
for(j=0;j<n;++j)
scanf("%d",&a[j]);
Qsort(a,0,n-1);for(j=0;j<n;++j)
printf("%5d",a[j]);printf("/n");
getch();
}
2、用C语言实现下列各种操作
1) 单链表的建立
2) 在第i个结点之前插入一个结点
3) 删除第i个结点
#define NULL 0
typedef struct node{
int
data;
struct node *next;
}node,*link;
/*单链表建立
void crealink(link *L,int n)
{link p,q;
int i;
*L=(link)malloc(sizeof(node));
q=*L;
q->next=NULL;
for(i=1;i<=n;++i)
{p=(link)malloc(sizeof(node));
printf("input p->data=");
scanf("%d",&p->data);
p->next=NULL;
q->next=p;
q=p;
}
}
/*单链表的输出*/
void print(link L)
{link p;
p=L->next;
while(p)
{printf("%5d",p->data);
p=p->next;
}
printf("/n");
}
/*在单链表的第I 个位置上插入元素值为e 的函数*/
void insert(link *L,int i,int e)
{link p,s;
int j=0;
p=*L;
/*找被插入位置,p指向i-1位置*/
while(p&&j<i-1)
{p=p->next;++j;}
if(!p||j>i)
printf("error");
else{
/*申请结点*/
s= (link)malloc(sizeof(node));
s->data=e;
/*插入*/
s->next=p->next;
p->next=s;
}
}
/*删除单链表的第I 个位置上的元素值*/
void delink(link *L,int i)
{link p,s;
int j=0;
p=*L;
/*查找被删位置,p指向i-1位置*/
while(p&&j<i-1)
{p=p->next;++j;}
if(!p||j>i)
printf("error");
else{
s=p->next;/S指向被删结点*/
p->next=s->next;
free(s);
}
}
main()
{link L;
int n,i,e;/*链表结点的个数*/
printf("input link n=");
scanf("%d",&n);
crealink(&L,n);
print(L);
/*i表示被插位置*/
printf("input i=");
scanf("%d",&i);
/*i表示被插值*/
printf("input e=");
scanf("%d",&e);
insert(&L,i,e);
print(L);
/*i表示被删位置*/
printf("input i");
scanf("%d",&i);
delink(&L,i);
print(L);
getch();
}
3、用C语言实现下列各种操作
1) 二叉树的建立用递归法
2) 用递归方法对二叉树进行全序、中序、后序遍历及用非递归方法对树进行层次遍历
#define NULL 0
/*定义二叉树中的结点*/
typedef struct node
{char data;
struct node *lch,*rch;
}node,*link;
/*用先序遍历的思想建立二叉树*/
void creat(link *t)
{char ch;
scanf("%c",&ch);
if(ch=='0') *t=null;
else
{
*t=(link)malloc(sizeof(node));
(*t)->data=ch;
creat(&(*t)->lch);
creat(&(*t)->rch);
}
}
/*先序遍历函数*/
void preorder(link t)
{
if(t!=null)
{ printf("%c",t->data);/*访问根结点*/
inorder(t->lch);/* 先序遍历左子树*/
inorder(t->rch);/* 先序遍历右子树*/
}
}
/* 中序遍历函数*/
void inorder(link t)
{
if(t!=null)
{
inorder(t->lch);/* 中序遍历左子树*/
printf("%c",t->data); /*访问根结点*/
inorder(t->rch); /* 中序遍历右子树*/
}
}
/*后序遍历函数*/
void postorder(link t)
{
if(t!=null)
{
postorder(t->lch); /* 后序遍历左子树*/
postorder(t->rch); /*访问根结点*/
printf("%c",t->data); /*后序遍历右子树*/
}
}
/*二叉树的层次遍历*/
void lever(link t)
{ link
p;
/*定义空队列*/
bitree Q[100];
int front=0,rear=0;
/*初始化队列为空队列*/
Q[rear++]=t;
/*当队列为非空时*/
while(front!=rear)
{ p=Q[front++];/*对头元素出队列*/
printf("%5d",p->data);
/*对头元素左孩子不空,将左孩子入队列*/
if(p->lch!=NULL)
Q[rear++]=p->lch;
/*对头元素左孩子不空,将左孩子入队列*/
if(p->rch!=NULL)
Q[rear++]=p->rch;
}
}
main()
{
link t;
creat(&t);
prorder(t);
printf("/n");
inorder(t);
printf("/n");
postorder(t);
printf("/n");
lever(t);
printf("/n");
getch();
}
4、用C语言实现下列各种操作
1) 用邻接表法建立有向图的邻接表
2) 用深度优先和广度优先法来遍历该有向图
#define NULL 0
/*定义访问数组*/
int visited[100];
/*邻接点及顶点的定义*/
typedef struct node
{int adjvex;
struct node *next;}node;
/*顶点的定义*/
typedef struct
{int vex;
node *firstadj;
}vertex;
/*邻接表的定义*/
typedef struct
{ vertex data[100];
int
m ;/*m表示图中顶点的个数*/
} adjlist;
/*void creategraph(adjlist *g)
功能:建立有向图的邻接表,图中的边由键盘给出。
void dfs(adjlist
g)
功能:完成有向连通图的深度优先遍历。
void bfs(adjlist
g)
功能:完成有向连通图的广度优先遍历。
有向图的邻接表的建立程序*/
void creategraph(adjlist *g)
{int
n,e; /*n表示图中的顶点个数,e表示边的条数*/
int j,i,k;
node *p,*q;
/*由键盘输入图的顶点个数及边的条数*/
printf("input n=");
scanf("%d",&n);
printf("input e=");
scanf("%d",&e);
/*初始化邻接表*/
g->m=n;
for(j=0;j<=n-1;++j)
{g->data[j].firstadj=NULL;
g->data[j].vex=j;
}
for(j=0;j<e;++j)
{/*由键盘输入一对边*/
printf("input i,k:");
scanf ("%d%d",&i,&k);
/*申请一个邻结点*/
p=(node *)malloc(sizeof(node));
p->adjvex=k;
p->next=NULL;
if(g->data[i].firstadj==NULL)
g->data[i].firstadj=p;
else
{q=g->data[i].firstadj;
while(q->next)
q=q->next;
q->next=p;
}
}
}
/* 有向图的深度优先遍历*/
void dfs(adjlist g, int v )
{node *p;
printf("%3d",v);
visited[v]=1;
p= g.data[v].firstadj;
while(p)
{if(visited[p->adjvex]==0) dfs(g , p->adjvex);
p=p->next;
}
}
/*有向图的广度优先遍历程序*/
void bfs(adjlist g, int v )
{/*定义空队列*/
int Q[100];
int front=0,rear=0;
node *p;
visited[v]=1;
printf("%3d",v);
Q[rear++]=v;
while(front!=rear)
{v=Q[front++];
p= g.data[v].firstadj;
while(p)
{if(visited[p->adjvex]==0)
{ visited[p->adjvex]=1;
printf("%3d", p->adjvex);
Q[rear++]= p->adjvex;
}
p=p->next;
}
}
}
/*主函数如下:*/
main()
{adjlist g;
int
i;
creategraph(&g);
/*初始化访问数组*/
for(i=0;i<g.m;++i) visited[i]=0;
dfs(g, 0);
printf("/n");
/*初始化访问数组*/
for(i=0;i<g.m;++i) visited[i]=0;
bfs(g , 0);
getch();
}
5、迷宫程序
#define
m 6
#define
n 9
void
path()
{/*定义迷宫并初始化迷宫*/
int maze[8][11]={1,1,1,1,1,1,1,1,1,1,1,
1,0,1,0,0,0,1,1,0,0,1,
1,1,0,0,0,1,1,0,1,1,1,
1,0,1,1,0,0,0,0,1,1,1,
1,1,1,0,1,1,1,1,0,1,1,
1,1,1,0,1,0,0,1,0,0,1,
1,0,0,1,1,1,0,1,1,0,1,
1,1,1,1,1,1,1,1,1,1,1}
;
int
move[9][2];
/*定义栈*/
int
s[54][3];
int top=0;
int
i,j,k,p,f=0,g,h;
/*初始化增量矩阵*/
move[1][0]=-1; move[1][1]=0;
move[2][0]=-1; move[2][1]=1;
move[3][0]=0; move[3][1]=1;
move[4][0]=1; move[4][1]=1;
move[5][0]=1; move[5][1]=0;
move[6][0]=1; move[6][1]=-1;
move[7][0]=0; move[7][1]=-1;
move[8][0]=-1;move[8][1]=-1;
maze[1][1]=2;
/*初始化栈非空*/
s[top][0]=1;
s[top][1]=1;
s[top][2]=3;
++top;
while (top!=0&&f==0)
{/*退栈*/
--top;
i=s[top][0];
j=s[top][1];
k=s[top][2];
/*当方向数小于8时*/
while(k<=8)
{/*试老鼠的下一位置*/
g=i+move[k][0];
h=j+move[k][1];
if (g==m&&h==n&&maze[g][h]==0)
{for(p=0;p<top;++p)
{
printf("%d,%d,%d/n",s[p][0],s[p][1],s[p][2]);}
printf("%d,%d,%d/n",i,j,k);
printf("%d,%d,%d/n",m,n,k);
f=1;
}
if(maze[g][h]==0)
{maze[g][h]=2;
/*下一位置可通,将上一位置入栈*/
s[top][0]=i;
s[top][1]=j;
s[top][2]=k;
++top;
/*改变老鼠的当前位置*/
i=g;
j=h;
k=0;
}
/*方向数增1*/
k=k+1;
}
}
if(f==0)
printf("no path/n");
}
main()
{
path();
getch();
}
6、约瑟夫问题程序
#define NULL 0
typedef struct QNode
{int data;
struct QNode *next;
}QNode,*linklist;
/*建立循环链表*/
void create(linklist *L,int
n)
{int i ;
linklist
p,q;
*L=(QNode*) malloc(sizeof(QNode));
(*L)->next=NULL;
q=*L;
for(i=1;i<=n;++i)
{p=(QNode*) malloc(sizeof (QNode));
p->data=i;
q->next=p;q=p;
}
q->next=(*L)->next; *L=(*L)->next;
}
/*输出循环链表*/
void print(linklist L)
{linklist p;
p=L;
while(p->next!=L)
{printf("%5d",p->data);
p=p->next;
}
printf("%5d",p->data);
printf("/n");
}
/*报数到第m号出圈*/
void
jone(linklist L,int m)
{linklist p,q; int i, j;
p=L;
/*将指针定位到k-1号位*/
for(i=1;i<k;++i)
p=p->next;
/*从第k号位置开始报数,k报1号,k+1报2号,依次类推,将指针指向最后一个报数的人*/
while(p->next!=p)
{j=1;
while(p->next!=p&&j<m-1)
{p=p->next;++j;}
q=p->next;
printf("%5d",q->data);
/*删除第m号*/
p->next=q->next;
p=p->next;
free(q);
}
printf("/nzuihou yige shi:%5d",p->data);
}
main()
{linklist L;
create(&L,100);
print(L);
jone(L,10);
getch();
}
7、Kruskal算法的设计
[
实验目的]
1. 根据算法设计需要
, 掌握连通网的灵活表示方法;
2. 掌握最小生成树的Kruskal算法
;
3. 基本掌握贪心算法的一般设计方法
;
4. 进一步掌握集合的表示与操作算法的应用
.
[
预习要求]
1. 认真阅读算法设计教材和数据结构教材内容
, 熟习连通网的不同表示方法和最小生成树算法;
2. 设计Kruskal算法实验程序
.
[
参考数据类型或变量]
typedef NodeNumber int; /* 节点编号 */
typedef CostType int; /* 成本值类型 */
typedef ElemType NodeNumber /* 实型或任意其它元素类型 */
typedef struct { int ElemType; int tag; }NODE;
typedef struct { CostType cost; NodeNumber node1, node2; }EDGE;
NODE set[]={{1,-1},…,{n,-1}}; /* 节点集
, n为连通网的节点数 */
EDGE es[ ]={{values of e1},…,{ values of em}}; /* 边集
, m为连通网的边数 */
EDGE st[n-1]; /* 最小生成树的边集 */
[
参考子程序接口与功能描述]
int Find(NODE *set, ElemType elem)
功能: 在数组set中顺序查找元素elem, 如果不成功, 返回-1; 否则, 使用带压缩规则的查找算法,返回所在子集的根节点索引.
int Union(NODE *set, ElemType elem1, ElemType elem2)
功能: 应用Find算法首先找到elem1和elem2所在的子集, 然后应用带加权规则的并运算算法合并两个子集. 不成功时, 返回-1; 否则, 返回并集的根节点索引.
void Sort(EDGE *es, int n)
功能: 用任意分类算法将连通图的边集按成本值的非降次序分类.
void Kruskal(EDGE *es, int m, NODE *set, int n, EDGE *st)
功能: 对有n个节点, m条边的连通网, 应用Kruskal算法生成最小生成树, 最小生成树的边存储在数组st中.
void Output(EDGE *st, int n)
功能: 输出最小生成树的各条边.
[
实验步骤]
1. 设计测试问题
,修改并调试程序, 输出最小生成树的各条边, 直至正确为止
;
2. 待各功能子程序调试完毕
, 去掉测试程序, 将你的程序整理成功能模块存盘备用.
[
实验报告要求]
1. 阐述实验目的和实验内容
;
2. 阐述Kruskal算法的原理方法;
3. 提交实验程序的功能模块
;
4. 提供测试数据和相应的最小生成树
.
[
思考与练习]
1. 设计由连通网初始边集数组生成最小堆的算法
;
2. 设计输出堆顶元素
, 并将剩余元素调整成最小堆的算法;
3. 针对连通网初始边集最小堆表示
, 设计Kruskal算法;
4. 采用成本邻接矩阵表示连通网时
, 在剩余边中如何实现最小成本边的查找?
5. 采用成本邻接矩阵表示连通网时
, 用C语言实现Prim算法
.
8、
实验六
回溯算法设计
[
实验目的]
1. 掌握回溯法解题的基本思想;
2. 掌握回溯算法的设计方法;
3. 针对子集和数问题,熟练掌握回溯递归算法、迭代算法的设计与实现。
[
预习要求]
1. 认真阅读教材或参考书
, 掌握回溯法解题的基本思想, 算法的抽象控制策略;
2. 了解子集和数问题及解向量的定长和变长状态空间表示;
3. 针对解向量的定长表示
, 设计状态空间树节点扩展的规范(限界)函数及实现方法;
4. 分析深度优先扩展状态空间树节点或回溯的条件;
5. 分析和设计生成解向量各分量可选值的实现方法;
6. 设计和编制回溯算法的递归和迭代程序。
[
参考数据类型或变量]
float s; // 表示有可能抵达答案节点的子路径上的元素之和;
float r; // 尚未测试的剩余集合元素之和;
float w[n]; // 存储原始集合的n个元素
, 根据问题实例初始化;
int x[n]; // 定长表示的解向量
, 各元素初始值为0;
[
参考子程序接口与功能描述]
void RecursiveSubset(float s, float r, int k)
功能: 针对问题实例的递归回溯算法。
void IterativeSubset(float s, float r, int k)
功能: 针对问题实例的迭代回溯算法。
void InitializeInstanse(void)
功能
: 问题实例的初始化函数, 初始化子集和数M , w, x向量, s, r。
[
实验步骤]
1. 录入、修改并测试你的程序,直至正确为止;
2. 针对问题实例,实录运行时的输入、输出界面;
3. 将你的程序和实录的界面存盘备用。
[
实验报告要求]
1. 阐述实验目的和实验内容;
2. 提交模块化的实验程序源代码;
3. 简述程序的测试过程,提交实录的输入、输出界面;
4. 鼓励对实验内容展开讨论,鼓励提交思考与练习题的代码和测试结果。
[
思考与练习]
1. 试针对解向量的变长表示设计回溯算法,上机测试正确性。
2. 试针对0/1背包问题设计回溯算法,比较与子集和数问题的算法差异。