写在前面
本文提供数据结构课程实验之链表、二叉树相关内容,包括实验任务、核心代码和运行结果。若想获取完整实验报告和用于验收的可运行源代码,请点击下方链接跳转:
《数据结构》实验报告/源代码:链表与二叉树
实验一:链表
(一)实验目的
- 理解线性表的链式存储结构。
- 熟练掌握动态链表结构及有关算法的设计。
- 根据具体问题的需要,设计出合理的表示数据的链表结构,并设计相关算法。
(二)实验任务
- 对任意输入的一组数据,建立一个递增有序的单链表。
- 将单链表拆分成两个单链表,其中一个全为奇数,另一个全为偶数(尽量利用原存储空间)。
- 把单链表中的元素就地逆置(利用原表各结点的空间)。
- 用递增有序的链表A、B表示两个集合,设计算法求它们的并集。
- 删除非空的单循环链表的表尾结点。
- 判断一个双循环链表是否对称。
(三)实验方案及运行结果
- 对任意输入的一组数据,建立一个递增有序的单链表。
- 核心算法:
void list::display() {
node* p = head->next;
while (p != NULL) { cout << p->data << " "; p = p->next; }
cout << endl;
}
void list::insert1(int 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++;
}
}
- 运行结果:
2. 将单链表拆分成两个单链表,其中一个全为奇数,另一个全为偶数(尽量利用原存储空间)。
- 核心算法:
void list::devide(list* L, list* L1, list* L2)
{
int x, i;
for (i = 1; i < L->length() + 1; i++) {
L->get_element(i, x);
if (i % 2 != 0) {
int j = 1;
L1->insert(j, x);
}
else {
int j = 1;
L2->insert(j, x);
}
}
}
int main() {
list L, L1, L2;
L.create1();
cout << "链表为:" << endl;
L.display();
L.devide(&L,&L1,&L2);
cout << endl;
cout << "链表的奇数项为:" << endl;
L1.display();
cout<<endl;
cout << "链表的偶数项为:" << endl;
L2.display();
cout << endl;
return 0;
}
- 测试结果:
3. 把单链表中的元素就地逆置(利用原表各结点的空间)。
- 核心算法:
void ReverseList(Seqlist &L)
{
int t;
if(L.length%2==0) //顺序表元素个数为偶数
{
for(int i=0;i<L.length/2;i++)
{
t=L.pdata[i];
L.pdata[i]=L.pdata[L.length-i-1];
L.pdata[L.length-i-1]=t;
}
}
else if(L.length%2==1) //顺序表元素个数为奇数
{
for(int i=0;i<(L.length-1)/2;i++)
{
t=L.pdata[i];
L.pdata[i]=L.pdata[L.length-i-1];
L.pdata[L.length-i-1]=t;
}
}
}
int main()
{
Seqlist L;
InitList(L); //初始化
CreateList(L); //建立
cout<<"顺序表元素为:"<<endl;
ListTraverse(L); //原序输出
ReverseList(L); //逆置
cout<<"逆置后的顺序表元素为:"<<endl;
ListTraverse(L); //逆置输出
return 0;
}
- 测试结果:
4. 用递增有序的链表 A 、B 表示两个集合,设计算法求它们的并集。
- 核心算法:
void list:: minus_LinkList(list A,list B,list &C)
{
node* tempA = A.get_head()->next;
node* tempB = B.get_head()->next;
node* tempC = C.get_head();
int x;
while (tempA != NULL)
{
node* s = new node;
s->data = tempA->data;
tempC->next = s;
tempC = s;
tempC->next = NULL;
tempA = tempA->next;
}
tempC = C.get_head();
while (tempB != NULL)
{
x = tempB->data;
if (C.locate(x) == NULL)
{
node* s = new node;
s->data = x;
s->next = tempC->next;
tempC->next = s;
}
tempB = tempB->next;
}
}
int main() {
list A, B, C;
cout << "请输入L1:(以0结束)" << endl;
A.create2();
cout << "请输入L2:(以0结束)" << endl;
B.create2();
A.minus_LinkList(A, B, C);
C.display();
return 0;
}
- 测试结果:
5. 删除非空的单循环链表的表尾结点。
- 核心算法:
void LinkList::DelateTail()//删除表尾结点
{
node *p,*q;
p=q=rear->next;
while(p->next!=rear)
{
p=p->next;
}
p->next=q;
delete rear;
rear=p;
}
void LinkList::PrintLinkList()//打印单链表
{
node *p;
p=rear->next;
cout<<"链表中的元素为:"<<endl;
while(p!=rear)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<p->data<<endl;
}
- 运行结果:
6. 判断一个双循环链表是否对称
- 核心算法:
int main()
{
list l;
node* h;
h=l.create2(h);
l.showlist2();
cout<<endl;
bool sym=l.symmetry(h);
cout<<sym;
return 0;
}
- 测试结果:
实验二:二叉树
(一)实验目的
- 掌握二叉树的动态链表存储结构及表示。
- 掌握二叉树的三种遍历算法。
- 运用二叉树三种遍历的方法求解有关问题。
(二)实验任务
- 建立一棵采用二叉链表结构存储的二叉树。
- 分别对该二叉树进行先序、中序和后序遍历。
- 设计算法以输出二叉树中先序序列的前 k ( k >0)个结点的值。
- 求二叉树的高度。
- 求二叉树中叶子结点的数目。
- 按中序方式输出二叉树中各结点的值及其层次数。
- 复制一棵二叉树 T 到T1。
- 交换二叉树中每个结点的左右孩子指针的值。
(三)实验方案及运行结果
1.建立一棵采用二叉链表结构存储的二叉树,分别对该二叉树进行先序、中序和后序遍历
- 核心算法:
void BinaryTree::visit(bnode* T) //访问结点函数
{
cout << T->data;
}
void BinaryTree::preorder(bnode* T) //先序遍历
{
if (T != NULL) {
visit(T);
preorder(T->lchild);
preorder(T->rchild);
}
}
void BinaryTree::inorder(bnode* T) //中序遍历
{
if (T != NULL)
{
inorder(T->lchild);
visit(T);
inorder(T->rchild);
}
}
void BinaryTree::postorder(bnode* T) //后序遍历
{
if (T != NULL)
{
postorder(T->lchild);
postorder(T->rchild);
visit(T);
}
}
- 测试结果:
2. 设计算法以输出二叉树中先序序列的前 k ( k >0)个结点的值
- 核心代码:
int main()
{
tree t;
bittree a=NULL;
t.create(a);
cin>>k;
t.preorder_k(a);
return 0;
}
- 运行结果:
3. 求二叉树的高度
- 核心算法:
int BinaryTree::treeheight(bnode* T) //递归法求树高
{
int height;
if (T == NULL)
return 0;
else
return max(treeheight(T->lchild), treeheight(T->rchild)) + 1 ;
}
- 测试结果:
4. 求二叉树中叶子结点的数目
- 核心算法:
int BinaryTree::DepthTree(bnode* root) //求叶子结点
{
if (!root)
{
return 0;
}
else
{
if ((!root->lchild) && (!root->rchild))
{
return 1;
}
else
{
return (DepthTree(root->lchild) + DepthTree(root->rchild));
}
}
}
- 测试结果:
5. 按中序方式输出二叉树中各结点的值及其层次数。
- 核心算法:
void BinaryTree::in_traverse_level(bnode*& T, int n)
{
//对中序遍历算法进行改造
if (T != NULL)
{
in_traverse_level(T->lchild, n + 1);
cout << "节点:" << T->data << " 该节点层次:" << n << endl;;
in_traverse_level(T->rchild, n + 1);
}
}
void BinaryTree::copy(bnode* T, bnode*& S)
{
if (T == NULL)
S = NULL;
else
{
S = new bnode;
S->data = T->data;
copy(T->lchild, S->lchild);
copy(T->rchild, S->rchild);
}
}
- 测试结果:
6.复制一棵二叉树 T 到T1
int main()
{
tree t;
bittree a=NULL;
bittree a1;
t.create(a);
t.copytree(a,a1);
t.preorder(a);
cout<<endl;
t.preorder(a1);
}
- 测试结果:
7. 交换二叉树中每个结点的左右孩子指针的值
- 核心代码:
void BinaryTree::Switch(bnode*& T1, bnode*& T2)
{
bnode* t = T1;
T1 = T2;
T2 = t;
}
void BinaryTree::NodeSwap(bnode*& T)
{
if (T != NULL)
{
if (T->lchild != NULL && T->rchild != NULL)/
{
Switch(T->lchild, T->rchild);
}
else if (T->lchild != NULL && T->rchild == NULL)/
{
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/
{
}
NodeSwap(T->lchild);
NodeSwap(T->rchild);
}
else
{
;
}
}
- 测试结果:
心得体会
-
通过双链表实验以及应用实验,对于链表这一数据结构理解更加深刻,对于头节点的作用更加明确,实验结果符合要求和逻辑。
-
熟练地掌握了二叉树的建立以及递归函数的调用,还了解了递归的逻辑以及终止条件。