《算法与数据结构》实验报告(CE专业,非CS)
这里给出的代码够完成实验了,一些简单的、书上的代码省去,如果想要完整的源码请点击: 算法与数据结构实验代码合集下载。
实验一
一、实验目的和要求∶
- 理解线性表的链式存储结构。
- 熟练掌握动态链表结构及有关算法的设计。
- 根据具体问题的需要,设计出合理的表示数据的链表结构,并设计相关算法。
- 理解单循环链表及双循环链表的特点,掌握这两种结构的算法设计。
二、实验任务∶
- 在一个递增有序的链表L中插入一个值为x的元素,并保持其递增有序特性。
// 第一题
void list::insert1(elementtype x) {
node *u, *P;
P = head;
while (P->next != NULL && P->next->data < x) //搜索插入位置
P = P->next;
if (P->next == NULL || P->next->data > x) { // 找到了位置
u = new node;
u->data = x;
u->next = P->next; //插入新结点
P->next = u;
count++;
}
}
int main() {
list l;
int x;
cout << "创建一个链表(输入‘-1’结束):" << endl;
l.create2();
cout << "输入要插入的数(输入‘-1’结束):" << endl;
cin >> x;
while (x != -1) {
l.insert1(x);
cin >> x;
}
l.display();
}
、
2. 将单链表L中的奇数项和偶数项结点分解开,并分别连成一个带头结点的单链表,然后再将这两个新链表同时输出在屏幕上,并保留原链表的显示结果,以便对照求解结果。
// 第二题
void list::divide(list &B, list &C) {
node *pa = head->next;
node *pb = B.get_head();
node *pc = C.get_head();
int i = 0;
while (pa != NULL){
node *u = new node; // u需要在循环里初始化
u->data = pa->data;
if (i % 2 == 0) {
pb->next = u;
pb = pb->next;
} else {
pc->next = u;
pc = pc->next;
}
pb->next = NULL;
pc->next = NULL;
i++;
pa = pa->next;
}
}
int main() {
list A, B, C;
A.create2();
A.divide(B, C);
cout << "原表: ";
A.display();
cout << "奇数表: ";
B.display();
cout << "偶数表: ";
C.display();
}
3. 递增有序单链表A和B表示两个集合,求解C=A∪B。
// 第三题
void list::unionset(list A, list B, list &C) {
cout << "求并集" << endl;
node *Pa, *Pb, *Rc;
Rc = C.get_head();
Pa = A.get_head()->next;
Pb = B.get_head()->next;
while (Pa != NULL && Pb != NULL) {
if (Pa->data < Pb->data) {
count++;
node *u = new node;
u->data = Pa->data;
Rc->next = u;
Rc = u;
Pa = Pa->next;
}
else if (Pa->data > Pb->data) {
count++;
node *u = new node;
u->data = Pb->data;
Rc->next = u;
Rc = u;
Pb = Pb->next;
}
else {
count++;
node *u = new node;
u->data = Pa->data;
Rc->next = u;
Rc = u;
Pa = Pa->next;
Pb = Pb->next;
}
}
while (Pa != NULL) {
count++;
node *u = new node;
u->data = Pa->data;
Rc->next = u;
Rc = u;
Pa = Pa->next;
}
while (Pb != NULL) {
count++;
node *u = new node;
u->data = Pb->data;
Rc->next = u;
Rc = u;
Pb = Pb->next;
}
Rc->next = NULL;
}
int main() {
list A, B, C;
cout << "创建一个链表(输入‘-1’结束):" << endl;
A.create2();
A.display();
cout << "===============================" << endl;
B.create2();
B.display();
cout << "===============================" << endl;
C.unionset(A,B,C) ;
C.display();
cout << "当前链表长度为" << C.length() << endl;
}
4. 设计算法判断单循环链表是否每个结点的值都是偶数。
// 第四题
bool list::is_even(list L) {
int x;
for (int i = 1; i <= L.length(); i++) {
L.get_element(i, x);
if (x % 2 != 0) {
return false;
}
}
return true;
}
int main() {
int ins_pos;
elementtype ins_ele, res;
list l;
cout << "创建一个链表(输入‘-1’结束):" << endl;
l.create2();
l.display();
cout << "===============================" << endl;
l.is_even(l) ? cout << "当前链表全为偶数" << endl : cout << "当前链表不全为偶数" << endl;
cout << "===============================" << endl;
cout << "输入要插入的位置、数据:" << endl;
cout << "enter:";
cin >> ins_pos >> ins_ele;
while (ins_ele != -1) {
l.insert(ins_pos, ins_ele);
cin >> ins_ele;
}
l.display();
cout << "===============================" << endl;
l.is_even(l) ? cout << "当前链表全为偶数" << endl : cout << "当前链表不全为偶数" << endl;
cout << "===============================" << endl;
}
5. 构造一个双循环链表,并判断它是否对称。(选做)
实验二
一、实验目的和要求∶
- 掌握二叉树的动态链表存储结构及表示。
- 掌握二叉树的三种遍历算法。
- 运用二叉树三种遍历的方法求解有关问题。
二、实验任务∶
- 建立一棵采用二叉链表结构存储的二叉树。
- 分别对该二叉树进行先序、中序和后序遍历。
- 求二叉树的高度。
- 求二叉树中叶子结点的数目。
- 按中序次序输出二叉树中各结点的值及其所对应的层次数。
- 复制一棵二叉树T到T1。
- 交换二叉树中每个结点的左右孩子指针的值。
代码
// 任务1:A B C # D # # E # F # # G H # # I # #
void BinaryTree::CreateBinaryTree(bnode *&T) {
char ch;
cin >> ch;
if (ch == '#') T = NULL;
else {
T = new bnode;
T->data = ch;
CreateBinaryTree(T->lchild);
CreateBinaryTree(T->rchild);
}
}
// 任务2:先序
void BinaryTree::preorder(bnode *T) {
if (T != NULL) {
visit(T);
preorder(T->lchild);
preorder(T->rchild);
}
}
// 任务2:中序
void BinaryTree::inorder(bnode *T) {
if (T != NULL) {
inorder(T->lchild);
visit(T);
inorder(T->rchild);
}
}
// 任务2:后序
void BinaryTree::postorder(bnode *T) {
if (T != NULL) {
postorder(T->lchild);
postorder(T->rchild);
visit(T);
}
}
// 前序遍历输出
void BinaryTree::preTraverse(bnode *T) {
if (T) {
cout << T->data << " ";
preTraverse(T->lchild);
preTraverse(T->rchild);
}
}
// 任务3:求二叉树的高度
int BinaryTree::high(bnode *T) {
if (T == NULL) return (0);
else return max(high(T->lchild), high(T->rchild)) + 1;
}
// 任务4:求二叉树中叶子结点的数目
int BinaryTree::leaf(bnode *T) {
if (T == NULL)
return 0;
if (T->lchild == NULL && T->rchild == NULL)
return 1;
return leaf(T->lchild) + leaf(T->rchild);
}
// 任务5:中序输出二叉树中各结点的值及其所对应的层次数
void BinaryTree::in_data_level(bnode *T, int n) {
if (T != NULL) {
in_data_level(T->lchild, n + 1);
cout << "节点值:" << T->data << ",该节点层次:" << n << endl;
in_data_level(T->rchild, n + 1);
}
}
// 任务6:复制一棵二叉树T到T1
void BinaryTree::copy(bnode *T, bnode *&S) {
if (T != NULL) {
S = new bnode();
S->data = T->data;
copy(T->lchild, S->lchild);
copy(T->rchild, S->rchild);
}
}
// 任务7:交换二叉树中每个结点的左右孩子指针的值
void BinaryTree::NodeSwap(bnode *T) {
// 此算法根据二叉树先序遍历算法改造而来
if (T != NULL) {
// 如果T的左孩子和右孩子都不空
if (T->lchild != NULL && T->rchild != NULL) {
//将"交换二叉树每个结点的左孩子和右孩子"转换为"交换二叉树每个结点的左孩子的数据域和右孩子的指针域".
bnode *t = T->lchild;
T->lchild = T->rchild;
T->rchild = t;
} else if (T->lchild != NULL && T->rchild == NULL) { // 如果T的左孩子不空且右孩子为空
//将T的左子树变为右子树
T->rchild = T->lchild;
T->lchild = NULL;
} else if (T->lchild == NULL && T->rchild != NULL) { // 如果T的左孩子为空且右孩子不为空
//将T的右子树变为左子树
T->lchild = T->rchild;
T->rchild = NULL;
} else { //如果T的左孩子和右孩子都为空
// 空操作
}
NodeSwap(T->lchild);
NodeSwap(T->rchild);
}
}
int main() {
BinaryTree b,copy;
int x;
int level = 1;
bnode *broot = b.get_root();
bnode *copyroot = copy.get_root();
cout << "1.创建一个先序二叉树(输入#为空):" << endl;
b.CreateBinaryTree();
cout << "2.先序、中序、后序遍历" << endl;
cout << "3.二叉树高度" << endl;
cout << "4.二叉树中叶子节点数" << endl;
cout << "5.中序输出二叉树中各结点的值及其所对应的层次数:" << endl;
cout << "6.复制一棵二叉树T到T1" << endl;
cout << "7.交换二叉树中每个结点的左右孩子指针的值:" << endl;
cout << "输入你的选择(输入-1退出):";
cin >> x;
while (x != -1) {
switch (x) {
case 2:
cout << "先序遍历为:";
b.preorder();
cout << endl;
cout << "中序遍历为:";
b.inorder();
cout << endl;
cout << "后序遍历为:";
b.postorder();
cout << endl;
break;
case 3:
cout << "树的高度为:";
cout << b.high(b.get_root()) << endl;
break;
case 4:
cout << "叶子结点数为:";
cout << b.leaf(b.get_root()) << endl;
break;
case 5:
cout << "中序输出二叉树中各结点的值及其所对应的层次数:"<< endl;
b.in_data_level(b.get_root(),level);
break;
case 6:
cout << "复制一棵二叉树T到T1:"<< endl;
b.copy(b.get_root(), copyroot);
cout << "复制得到的新树的前序遍历为:";
copy.preTraverse(copyroot);
break;
case 7:
cout << "交换二叉树中每个结点的左右孩子指针的值:" << endl;
b.NodeSwap(b.get_root());
cout << "交换后的二叉树先序遍历为:";
b.preorder();
cout << endl ;
cout << "交换后的二叉树中序遍历为:";
b.inorder();
cout << endl ;
cout << "交换后的二叉树后序遍历为:";
b.postorder();
cout << endl ;
break;
}
cout << endl;
cout << "请继续选择(输入-1退出):";
cin >> x;
}
}
实验三
一、实验目的和要求∶
- 掌握图的基本概念。
- 掌握图的存储结构的设计与实现,基本运算的实现。
- 掌握图的两种遍历算法,以及遍历算法的应用
二、实验任务∶
- 分别以邻接矩阵和邻接表的存储结构建立图。
- 对图进行深度优先遍历。
- 求图中边(或弧)的数目。
- 判断图中的一个顶点是否为关节点。
- 判断一个有向图是不是一棵有向树。(任意一个顶点可能是根)
- 求顶点0到图中其余每个顶点的最短路径(以边数计算)。(选做)
代码
// 建立邻接表(无向图)
void graph::createadj() {
int i, j, k;
ednode *s;
// 输入顶点个数
cout << "请输入顶点个数:";
cin >> CurrentVertex;
cout<<"请输入各顶点的值:"<<endl;
for (k = 0; k < CurrentVertex; k++) {
// cout << "输入第" << k + 1 << "个顶点的值:";
cin >> vertex[k].verdata;
}
cout << "请输入边(输入-1 -1结束):" ;
cin >> i >> j;
while (i != -1) {
s = new ednode;
s->adjvex = j;
s->nextadj = vertex[i].firstadj;
//在顶点为 i 的邻接表中插入顶点为 j 的邻接点
vertex[i].firstadj = s;
s->adjvex = i;
s->nextadj = vertex[j].firstadj;
//在顶点为 j 的邻接表中插入顶点为 i 的邻接点
vertex[j].firstadj = s;
cout << "请输入边(输入-1 -1结束):" ;
cin >> i >> j;
}
}
int main() {
graph G;
cout << "用邻接表存储建立图:" << endl;
G.createadj();
cout << endl;
cout << "对图的深度优先遍历:" << endl;
G.Travel_DFS();
cout << endl;
}
// 建立邻接矩阵(无向图)
void graph::createadj() {
int i, j, k;
cout << "请输入顶点个数:";
cin >> CurrentVertex;
cout << "请输入各顶点的值:" << endl;
for (k = 0; k < CurrentVertex; k++)
cin >> vertex[k];
cout << "请输入边(输入-1 -1结束):";
cin >> i >> j;
while (i != -1) {
edge[i][j] = edge[j][i] = 1;
cout << "请输入边(输入-1 -1结束):";
cin >> i >> j;
}
}
// 从 v 点出发进行深度优先遍历
void graph::dfs(int v) {
int w;
visit(v);
visited[v] = true;
w = firstadj(v);
while (w != -1) {
if (!visited[w])
dfs(w);
w = nextadj(v, w);
}
}
// 任务2:深度优先遍历图
void graph::Travel_DFS() {
int i;
for (i = 0; i < CurrentVertex; i++)
visited[i] = false;
for (i = 0; i < CurrentVertex; i++)
if (!visited[i])
dfs(i);
}
// 任务3:求图中边(或弧)的数目
void graph::beforeedge(int v) {
int w;
visited[v] = true;
w = firstadj(v);
while (w != -1) {
E++;
if (!visited[w]) beforeedge(w);
w = nextadj(v, w);
}
}
int graph::edgenum() {
E = 0;
for (int i = 0; i < CurrentVertex; i++)
visited[i] = false;
for (int i = 0; i < CurrentVertex; i++)
if (visited[i] == false)
beforeedge(i);
return E / 2;
}
// 任务4:判断图中的一个顶点是否为关节点
/*
* 关节点是指在某图中,如果删除顶点V以及V相关的边后,
* 图的一个连通分量分割为两个或两个以上的连通分量,
* 则称顶点V为该图的一个关节点。
* */
int graph::numofGC() {
int i;
int k = 0; // k 用于连通分量的计数
for (i = 0; i < CurrentVertex; i++)
visited[i] = false;
for (i = 0; i < CurrentVertex; i++)
if (visited[i] == false) {
k++; // 用 k 来累计连通分量个数
beforeedge(i);
}
return k;
}
// 删除一个顶点的边
bool graph::deleteside(elementtype v){
int i;
for(i = 0;i < CurrentVertex;i++){
if(v < 0 || v >= CurrentVertex)
return false;
edge[v][i] = edge[i][v] = 0;
}
return true;
}
// 任务5:判断一个有向图是不是一棵树(任意一个顶点可能是根)
/*
* 判断有向图是不是有向树:
* 1.有且仅有一个节点,入度为0,即为根
* 2.其他节点,入度皆为1
* 3.从根开始广度搜索 所遍历的节点数应当与有向图中的节点数相等
* */
void graph::istree() {
int a, b, c;
a = b = c = 0;
for (int i = 0; i < CurrentVertex; i++) {
for (int j = 0; j < CurrentVertex; j++) {
if (edge[j][i] == 1)
a++;
}
if (a == 0) b++;
if (a == 1) c++;
a = 0;
}
if (b == 1 && c == CurrentVertex - 1)
cout << "该有向图是有向树" << endl;
else
cout << "该有向图不是有向树" << endl;
}
int main() {
graph g,g1;
int v,x,beforedel,afterdel,diff;
cout << "1.建立图:" << endl;
g.createadj();
cout << "2.对图深度优先遍历" << endl;
cout << "3.求图中边(或弧)的数目" << endl;
cout << "4.判断图中的一个顶点是否为关节点" << endl;
cout << "5.判断一个有向图是不是一棵树(任意一个顶点可能是根)" << endl;
cout << "输入你的选择(输入-1退出):";
cin >> x;
while (x != -1) {
switch (x) {
case 2:
cout << "本图的深度遍历为:";
g.Travel_DFS();
cout << endl;
break;
case 3:
cout << "图中边的数目为:" << g.edgenum() << endl;
break;
case 4:
g1 = g;
cout << "输入要判断的顶点:" << endl;
cin >> v;
beforedel = g1.numofGC();
cout << "删除顶点" << v << "的边前,连通分量有" << beforedel << "个" << endl;
g1.deleteside(v);
afterdel = g1.numofGC();
cout << "删除顶点" << v << "的边后,连通分量有" << afterdel << "个" << endl;
diff = afterdel - beforedel;
if (diff > 1)
cout << "顶点" << v << "是关节点" << endl;
else if ((diff == 0) || (diff == 1))
cout << "顶点" << v << "不是关节点" << endl;
else
cout << "error!" << endl;
break;
case 5:
cout << "判断一个有向图是不是一棵树:" << endl;
g.istree();
break;
}
cout << endl;
cout << "请继续选择(输入-1退出):";
cin >> x;
}
}