前言
记录实验,同时也是记录常见数据结构算法的实现。
广州大学学生实验报告
开课实验室:计算机科学与工程实验(电子楼418A)
学院 计算机科学与网络工程学院
实验课程 数据结构实验
实验项目 实验一 线性表、堆栈和队列的操作与实现
- 一、实验目的:
1、线性表的链表实现:遍历、查找、插入、删除、翻转
2、栈的链式存储结构实现:入栈、出栈
3、队列的链式存储结构的实现:入队、出队
4、线性表、栈和队列的应用实现 - 二、使用仪器、器材
微机一台
操作系统:WinXP
编程软件:C++ - 三、实验内容及原理
1、线性表的链表实现:(返回目录🖱)
// DataStruct_experiment.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// StructExperiment.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
typedef struct LNode
{
int data;
LNode* next;
}LNode, * LinkList;
//插入
void Insert(LinkList &l, LNode* new_node, int n)
{
// 头结点处不可插入值。判断插入的位置是否为头结点
while (1)
{
if (n == 0)
{
cout << "0处是头结点,请重新输入你想插入整数的位置\t位置: ";
cin >> n;
}
else if (n > 11 || n < 1)
{
cout << "输入的位置超出链表的长度,请重新输入...\t位置: ";
cin >> n;
}
else break;
}
// 寻找n-1处的节点
LNode* p = new LNode;
p = l;
if (p == NULL)
{
cout << "空表,退出程序......";
exit(0);
}
int i = 0;
while (i < n - 1 && p)
{
p = p->next;
++i;
}
// 在n处插入新节点,使原来在n处的节点变成n+1
new_node->next = p->next;
p->next = new_node;
cout << "在 " << setw(2) << n << " 处插入值为 " << new_node->data << " 的节点" << endl;
}
//输出链表的内容
void List_show(LinkList& l)
{
// 判断链表是否为空
if (!(l->next))
{
cout << "出错,此链表为空链表,退出程序......";
exit(0);
}
else
{
LNode* p = new LNode;
p = l->next;
cout << "链表为:";
for (int i = 1; p; i++)
{
if (p->next)
cout << p->data << "——";
else cout << p->data << "\t长度为:" << i << endl;
p = p->next;
}
}
}
//查找
void Search_in_list(LinkList& l)
{
int element;
cout << "请输入你想查找的整数: " << endl;
cout << "————若想退出查找,请输入0————" << endl;
LNode* p = new LNode;
p = l->next;
if (!p)
{
cout << "出错,此链表为空链表,退出程序......";
exit(0);
}
else
{
while (cin >> element)
{
if (element == 0)
{
cout << "退出查找......" << endl;
break;
}
else
{
int index_not_in = 0; //用于判断查找的值是否在链表中
for (int i = 1; p; i++)
{
if (p->data == element)
{
cout << "该整数在表中,且位置为" << i << endl;
cout << "请再次输入你想查找的整数: " << endl;
cout << "————若想退出查找,请输入0————" << endl;
}
else ++index_not_in;
p = p->next;
if (i == index_not_in && p == NULL) //到达链尾时,如果还找不到,说明这个整数不在这个链表中
{
cout << "整数" << element << "不在此链表中" << endl;
cout << "请再次输入你想查找的整数: " << endl;
cout << "————若想退出查找,请输入0————" << endl;
}
}
}
p = l->next;
}
}
}
//删除
void Delete(LinkList& l)
{
// 头结点处无数据,且不可删除。判断要删除的位置是否为头结点
int n;
cin >> n;
while (1)
{
if (n == 0)
{
cout << "0处是头结点,请重新输入你想删除的结点的位置\t位置: ";
cin >> n;
}
else if (n > 10 || n < 1)
{
cout << "输入的位置超出链表的长度,请重新输入...\t位置: ";
cin >> n;
}
else
{
cout << endl;
break;
}
}
// 寻找n处的节点
LNode* p = new LNode;
p = l;
int i = 0;
if (p->next == NULL)
{
cout << "出现错误,退出程序......";
exit(0);
}
while (i < n - 1 && p)
{
p = p->next;
++i;
}
// 删除n处的结点,使原来在n-1处的节点变成n
LNode* temp_p = p->next;
p->next = p->next->next;
cout << "在 " << setw(2) << n << " 处删除值为 " << temp_p->data << " 的节点" << endl;
delete temp_p;
}
// 翻转
void Reverse(LinkList& l)
{
LNode* p = new LNode;
p = l;
p = p->next; // p为链表中的第一个结点
if (p == NULL)
{
cout << "该链表为空链表,退出程序......";
exit(0);
}
LNode* p_backward, * p_forward;
p_backward = NULL;
while (p)
{
p_forward = p->next;
p->next = p_backward;
p_backward = p;
p = p_forward;
}
l->next = p_backward;
cout << "已翻转成功" << endl;
}
int main()
{
// (1)随机生成十个100~999的三位整数,并且存入链表中
srand((unsigned(time)));
LinkList l; // 链表l(英文字母l)
l = new LNode; // 头节点是链表的象征
l->next = NULL; // 初始化链表
cout << "(1)" << endl;
for (int i = 1; i <= 10; i++)
{
int random_int = rand() % 900 + 100;
LNode* p = new LNode;
p->data = random_int;
Insert(l, p, i);
}
// (2)输出链表的内容
cout << "(2)" << endl;
List_show(l);
// (3)读入一个整数,查看该整数是否在表中,若在,输出其位置,若不在,则说明一下不在
//加入了可多次输入整数进行判断的功能
cout << "(3)" << endl;
Search_in_list(l);
// (4) (1)中函数Insert()已经实现了该功能
cout << "(4)" << endl;
LNode* p1 = new LNode;
int location;
p1->data = 111; //默认插入的值为111
cout << "你想在链表的哪个位置插入新的元素?\t位置: ";
cin >> location;
Insert(l, p1, location);
List_show(l);
//(5)读入一个整数,若该整数在链表里,删除该整数,输出链表的内容;
cout << "(5)" << endl;
LNode* p2 = new LNode;
p2->data = 111; //默认插入的值为111
cout << "你想删除哪个位置的结点?\t位置: ";
Delete(l);
List_show(l);
// (6)
cout << "(6)" << endl;
Reverse(l);
List_show(l);
}
2、栈的链式存储结构实现(返回目录🖱)
#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
typedef struct LNode
{
int length;
int data;
LNode* next;
}LNode, * LinkStack;
void InitStack(LinkStack &s)
{
s->next = NULL;
s->length = 0;
cout << "链栈初始化成功,长度为0......" << endl;
}
void Push(LinkStack& s, int data)
{
LNode* p = new LNode;
p->data = data;
p->next = s->next;
s->next = p;
s->length++;
cout << "在位置" << setw(3) << s->length << "添加元素" << p->data << endl;
}
void Pop(LinkStack& s)
{
LNode* p = new LNode;
p = s->next;
s->next = p->next;
s->length--;
cout << "从栈中弹出元素 " << p->data <<setw(20)<<"深度为"<<s->length<< endl;
delete p;
}
//输出链栈的内容
void ShowListStack(LinkStack& s)
{
// 判断链表是否为空
if (!s->next)
{
cout << "栈空......退出程序......"<<endl;
exit(0);
}
else
{
LNode* p = new LNode;
p = s->next;
cout << "链栈为:" << endl;;
for (int i = 1; p; i++)
{
if (p->next)
cout <<"| " << p->data << " |\n"<<endl;
else cout << "| " << p->data << " |\n"<<"-------\t"<<"深度为:" << i << endl;
p = p->next;
}
}
}
int main()
{
srand(unsigned(time));
//初始化链栈
LinkStack s;
s = new LNode;
InitStack(s);
// 入栈
cout << "(1)\n";
for (int i = 0; i < 10; i++)
Push(s, rand() % 900 + 100);
ShowListStack(s);
// 出栈
cout << "(2)\n";
for (int i = 0; i < 10; i++)
Pop(s);
ShowListStack(s);
}
3、队列的链式存储结构的实现(返回目录🖱)
#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
//链队结点结构体
typedef struct LQNode
{
int data;
LQNode* next;
}LQNode, * LQNodeptr;
//链队结构体
typedef struct LinkQueue
{
LQNodeptr head;
LQNodeptr rear;
}LinkQueue;
//初始化
void InitLQ(LinkQueue &lq)
{
lq.head = lq.rear = new LQNode; //头结点
lq.head->next = lq.rear->next = NULL;
}
//入队
void Insert(LinkQueue &lq, int data)
{
LQNode* p = new LQNode;
p->data = data;
p->next = NULL;
lq.rear->next= p;
lq.rear = p;
cout << "在队尾加入结点: " << data << endl;
}
//输出链队
void ShowLQ(LinkQueue &lq)
{
LQNode* p = new LQNode;
p = lq.head->next;
cout << "链队:";
int length = 0;
while (p)
{
++length;
if (p != lq.rear)
cout << p->data << "—";
else cout << p->data << "\t长度为:"<<length<<endl;
p = p->next;
}
}
//翻转
void Reverse(LinkQueue &lq)
{
LQNode* p = new LQNode;
LQNode* q = new LQNode;
LQNode* r = new LQNode;
LQNode* p1 = new LQNode;
p = lq.head; // 头指针
p1 = p->next; // 先保存原链队的第一个结点,因为最后需要让尾指针指向它
q = p->next;
lq.head->next = NULL;
while (q)
{
r = q->next;
q->next = p;
p = q;
q = r;
}
lq.rear = p1;
p1->next = NULL;
lq.head->next = p; //将头指针指向尾指针的前一个结点
}
int main()
{
srand(unsigned(time));
LinkQueue lq;
InitLQ(lq);
//初始化
InitLQ(lq);
for (int i = 0; i < 10; i++)
{
Insert(lq, rand() % 900 + 100);
}
//输出队列
ShowLQ(lq);
//翻转
Reverse(lq);
//输出
ShowLQ(lq);
}
4、线性表、栈和队列的应用实现:(返回目录🖱)
(1) 用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
#include <iostream>
#include <ctime>
#include <iomanip>
using namespace std;
// 链式结点(可用于表示链表)
typedef struct LNode
{
int data;
LNode* next;
}LNode, * LinkList;
//链栈(用于声明链栈的头结点,头结点不含数据,故无data变量)
typedef struct Stack
{
LNode* next;
int depth;
} *LinkStack;
//往单链表中添加元素
void Insert_LinkList(LinkList& l, LNode* new_node, int n)
{
LNode* p = new LNode;
p = l;
for (int i = 1; i < n; i++)
{
p = p->next;
}
new_node->next = p->next;
p->next = new_node;
}
//输出单链表
void Show_LinkList(LinkList& l)
{
// 判断链表是否为空
if (!(l->next))
{
cout << "出错,此链表为空链表,退出程序......";
exit(0);
}
else
{
LNode* p = new LNode;
p = l->next;
cout << "链表为:";
for (int i = 1; p; i++)
{
if (p->next)
cout << p->data << "——";
else cout << p->data << "\t长度为:" << i << endl;
p = p->next;
}
}
}
//向栈中添加元素
void Push(LinkStack& s, int data)
{
LNode* p = new LNode;
p->data = data;
p->next = s->next;
s->next = p;
s->depth++;
//cout << "在位置" << setw(3) << s->depth << "添加元素" << p->data << endl;
}
//在栈中弹出元素
int Pop(LinkStack& s)
{
LNode* p = new LNode;
p = s->next;
s->next = p->next;
s->depth--;
//cout << "从栈中弹出元素 " << p->data << setw(20) << "深度为" << s->depth << endl;
return p->data;
}
//输出链栈的内容
void ShowListStack(LinkStack& s)
{
// 判断链表是否为空
if (!s->next)
{
cout << "栈空......退出程序......" << endl;
exit(0);
}
else
{
LNode* p = new LNode;
p = s->next;
cout << "链栈为:" << endl;;
for (int i = 1; p; i++)
{
if (p->next)
cout << "| " << p->data << " |\n" << endl;
else cout << "| " << p->data << " |\n" << "-------\t" << "深度为:" << i << endl;
p = p->next;
}
}
}
//以某值为基准把单链表分割为两部分
void Devide(LinkList& l,int n)
{
// 初始化装载大于n结点的栈 s_big
LinkStack s_big = new Stack;
s_big->next = new LNode;
s_big->next = NULL;
s_big->depth = 0;
// 初始化装载小于n结点的栈 s_small
LinkStack s_small = new Stack;
s_small->next = new LNode;
s_small->next = NULL;
s_small->depth = 0;
LNode* p = new LNode;
p = l->next;
//如果链表长度为0或1,则无法分割
if (p==NULL || p->next==NULL)
{
cout << "链表长度为0或1,无法分割...." << endl;
exit(0);
}
while (p)
{
int temp = p->data;
if (temp >= n)
{
Push(s_big, temp);
cout << "在元素 大 于"<<n<<"的栈的位置" << setw(3) << s_big->depth << "添加元素" << p->data << endl;
p = p->next;
}
else
{
Push(s_small, temp);
cout << "在元素 小 于" << n << "的栈的位置" << setw(3) << s_small->depth << "添加元素" << p->data << endl;
p = p->next;
}
}
ShowListStack(s_big);
ShowListStack(s_small);
LNode* p_ = new LNode;
p_ = l->next;
while (s_small->next)
{
p_->data = Pop(s_small);
cout << "从元素 小 于"<<n<<"的栈中弹出元素 " << p_->data << setw(20) << "此时 小 栈深度为" << s_small->depth << endl;
p_ = p_->next;
}
while (s_big->next)
{
p_->data = Pop(s_big);
cout << "从元素 大 于" << n << "的栈中弹出元素 " << p_->data << setw(20) << "此时 大 栈深度为" << s_big->depth << endl;
p_ = p_->next;
}
}
int main()
{
srand(unsigned(time));
LinkList l = new LNode;
l->next = NULL;
for (int i = 0; i < 10; i++)
{
LNode* p = new LNode;
p->data = rand() % 900 + 100;
Insert_LinkList(l, p, i + 1);
}
// 显示原链表
Show_LinkList(l);
//小的放300前面,大的放300后面
Devide(l, 300);
Show_LinkList(l);
cout <<"分割已完成。。。";
(2) 假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“…[…{…}…[…]…]…(…)” 为合法嵌套,“…[…{… )…[…]…]…(…)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。
#include<iostream>
using namespace std;
typedef struct SNode
{
char ch;
int depth;
SNode* next;
}SNode, *Stack;
void InitStack(Stack& s)
{
s = new SNode;
s->next = NULL;
s->ch = NULL;
s->depth = 0;
}
bool StackEmpty(Stack s)
{
if (s->next == NULL)
{
return true;
cout << "栈空..." << endl;
}
else return false;
}
void Push(Stack& s, char ch)
{
SNode* p = new SNode;
p->next = NULL;
p->ch = ch;
p->next = s->next;
s->next = p;
s->depth++;
cout << "在栈中放入字符 \"" << ch << "\" \t栈深度为:" << s->depth << endl;
}
void Pop(Stack& s)
{
SNode* p = new SNode;
p = s->next;
cout << "弹出元素" << p->ch << endl;
s->next = p->next;
delete p;
}
char GetTop(Stack s)
{
return s->next->ch;
}
bool Matching()
{
Stack s;
InitStack(s);
cout << "请键入字符...按#退出\t";
char ch;
int flag = 1;
cin >> ch;
while (ch!='#'&& flag)
{
switch (ch)
{
case'(':
case'[':
case'{':
{
Push(s, ch);
cout << "请继续键入字符...按#退出\t";
}; break;
case')':
if (!StackEmpty(s) && GetTop(s) == '(')
Pop(s);
else
{
flag = 0;
cout << "括号" << ch << "不匹配";
}; break;
case']':
if (!StackEmpty(s) && GetTop(s) == '[')
Pop(s);
else
{
flag = 0;
cout << "括号" << ch << "不匹配";
}; break;
case'}':
if (!StackEmpty(s) && GetTop(s) == '{')
Pop(s);
else
{
flag = 0;
cout << "括号" << ch << "不匹配";
}; break;
}
cin >> ch;
}
if (StackEmpty(s) && flag) return 1;
else return 0;
}
int main()
{
if (Matching()) cout << "匹配成功";
else cout << "匹配失败";
}
}
(3)用队列求解迷宫问题的最短路径
代码雏形出来了,但是调试了四个小时还是没解决那个关键bug……