数据结构实验一

****学生实验报告

开课学院及实验室:计算机科学与工程实验 20**年 ** 月 ** 日
学院 ************ 年级、专业、班 **** 姓名 *** 学号 **********
实验课程名称 数据结构 成绩 **
实验项目名称 实验一.线性表、堆栈和队列的操作与实现 指导老师 ***
评语:
一、实验目的
1、线性表的链表实现:遍历、查找、插入、删除、翻转
2、栈的链式存储结构实现:入栈、出栈
3、队列的链式存储结构的实现:入队、出队
4、线性表、栈和队列的应用实现
二、使用仪器、器材
微机一台
编程软件:C++
三、实验内容及原理
1、线性表的链表实现:
(1)用随机函数生成10个3位整数(100~999),把这些整数存于链表中;
//原理:1.用随机函数生成整数,并用前插法放在链表中
(2)输出链表的内容;
(3)读入一个整数,查看该整数是否在表中,若在,输出其位置(首位置为1);
//从链表的首元结点出发,依次将结点值和给定值e进行比较,返回查找结果
(4)读入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容(要求判断输入的位置是否合理);
(5)读入一个整数,若该整数在链表里,删除该整数,输出链表的内容;
(6)把链表的内容翻转,输出链表的内容。
//直接对链表进行翻转,不开辟新空间用来保存结点,只能改变指针的指向。

2、栈的链式存储结构实现
(1)用随机函数生成10个3位整数(100~999),把这些整数应用入栈操作存于堆栈中,在入栈接口处设置断点①,按“F5”启动调试,按“F10”逐句执行,直到数据全部入栈。程序暂停时观察栈顶数据和栈顶位置;
(2)应用出栈操作输出堆栈的内容,在出栈接口处设置断点②,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈,程序暂停时观察栈顶数据和栈顶位置的变化;
3、队列的链式存储结构的实现
(1)用随机函数生成10个3位整数(100~999),把这些整数应用入队操作存于队列中;
(2)应用遍历操作输出队列的内容;
(3)把队列的内容翻转,应用出队操作输出队列的内容。
翻转队列时,由于考虑到不破坏队列的性质,因此采用队列和堆栈结合的情况操作,通过将队列原有的元素出队列,进栈和出栈,重新进队列来实现翻转。
具体实现过程:
创建一个新结点,当队列不为空时,每个元素逐渐退出队列,并将其压入栈中,直至对列为空。然后弹出栈,并进入队列,直至栈为空,便实现了队列翻转.

4、线性表、栈和队列的应用实现:
(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
解决方案有两个:
1.用冒泡排序法从小到大排列一遍即可,不管它即将要插入的数据是谁,小的一定在大的后面
2.用两个指针跟踪链表,从首元结点开始,p,q同时指向L->next;当p非空且大于该读入的整数,q指向p,去遍历q,直到找到小于该整数,找到后,p,q数值互换,p继续遍历,直到p->next==NULL为止。
(2)假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“…[…{…}…[…]…]…(…)” 为合法嵌套,“…[…{… )…[…]…]…(…)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。
解决方案:
1.初始化一个空栈S。
2.设置一标记性变量flag,用来标记匹配结果以控制循环及返回结果,1表示正确匹配,0表示错误匹配,flag初值为1。
3.扫描表达式,依次读入字符ch,如果表达式没有扫描完毕或flag非零,则循环执行以下操作:
31. 若ch是左括号“[”或“(”,则将其压入栈;
32.若ch是右括号“)”,则根据当前栈顶元素的值分情况考虑:若栈非空且栈顶元素是“(”,则正确匹配,否则错误匹配,flag置为0;
33.若ch是右括号“]”,则根据当前栈顶元素的值分情况考虑:若栈非空且栈顶元素是“[”,则正确匹配,否则错误匹配,flag置为0。
4.退出循环后,如果栈空且flag值为1,则匹配成功,返回true,否则返回false。

(3)用队列求解迷宫问题的最短路径

<简要描述具体任务;填写程序设计中使用的数据结构及算法(算法思路和程序框架)>
四、实验过程原始数据记录
1、线性表的链表实现:
代码:
#include
#include
#include
#include
using namespace std;
typedef struct LNode
{
int data;
LNode* next;
}LinkList;
void CreateList_L(LinkList& L, int n)//前插法插入链表
{
L = new LNode;
L->next = NULL;
time_t t;
srand((unsigned)time(&t));
for (int i = n; i > 0; i–)
{
LinkList p = new LNode;
int rand_data = rand() % (1000 - 100) + 100;
p->data = rand_data;
p->next = L->next;
L->next = p;
}
}
int LocateElem_L(LinkList L, int e)//在线性表L中查找值为e的元素
{
LinkList p = L->next;
int j = 1;//首位置为1
while (p != NULL && p->data != e)
{
p = p->next;
j++;
}
if (p != NULL)
{
cout << “已经找到该整数,在位置” << " " << j << endl;//读出该整数在链表的位置
return j;
}
else
{
cout << “找不到该整数!” << endl;
return 0;
}
}
void ListInsert_L(LinkList& L, int i, int e)//在L中第i个元素之前插入数据元素e
{
LinkList p = L;
int j = 0;
while (p!=NULL && j < i - 1)//寻找第i-1个结点
{
p = p->next;
j++;
}
if (p == NULL || j > i - 1)//插入位置不合理
{
cout << “插入位置不合理!” << endl;
}
LinkList s = new LNode;//生成新节点S
s->data = e;//将结点的数据域置为e
s->next = p->next;//将结点s插入L中
p->next = s;
}
void ListDelete_L(LinkList& L, int i, int& e)
{
LinkList p = L;
int j = 0;
while (p->next && j < i - 1)
{
p = p->next;
++j;
}
if (p->next == NULL || j > i - 1)
{
cout << “删除位置不合理” << endl;
}
LinkList q = p->next;
p->next = q->next;
e = q->data;
delete q;
}
void Reverse(LinkList &L)
{
LinkList p = L->next;//p指向首元结点
L->next = NULL;//头结点指针域为空
while (p != NULL)//遍历链表,如果下一个结点存在
{
LinkList q = p->next;//q指向
p的后继
p->next = L->next;
L->next = p;//*p插入到头结点之后
p = q;//更新指针
}
}
int main()
{
LinkList L;
CreateList_L(L, 10);//初始化链表并用前插法将整数存入链表中
cout << “用随机函数生成10个3位整数,把这些整数存于链表中:” << endl;
for (LinkList p = L->next; p != NULL; p = p->next)//输出链表的内容
{
cout << p->data << " ";
}
cout << endl;
cout << endl;
cout << “查找输入的整数所在的链表中的位置,请输入该整数:” << endl;
int int1;
cin >> int1;
LocateElem_L(L, int1);//查找该整数所在的链表上的位置,若在,输出其位置(首位置为1)
cout << endl;
cout << “请输入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容” << endl;
int i, e;
cin >> i >> e;
ListInsert_L(L, i, e);
for (LinkList p = L->next; p != NULL; p = p->next)//输出链表的内容
{
cout << p->data << " ";
}
cout << endl;
cout << endl;
cout << “请输入一个整数,若该整数在链表里,删除该整数,输出链表的内容” << endl;
int j, f;
cin >> j >> f;
ListDelete_L(L, j, f);
for (LinkList p = L->next; p != NULL; p = p->next)//输出链表的内容
{
cout << p->data << " ";
}
cout << endl;
cout << endl;
cout << “把链表的内容翻转,输出链表的内容:” << endl;
Reverse(L);//翻转链表
for (LinkList p = L->next; p != NULL; p = p->next)//输出链表的内容
{
cout << p->data << " ";
}
cout << endl;
}
程序运行结果:

2、栈的链式存储结构实现
#include
#include
#include
#include
using namespace std;
typedef struct StackNode
{
int data;
struct StackNode* next;
}StackNode, * LinkStack;
void CoutStack(LinkStack S)
{
if (S->next == NULL)
{
return;
}
LinkStack p = S->next;
while (p != NULL && p->next != NULL)
{
cout << p->data << “->”;
p = p->next;
}
cout << p->data << “->NULL”;
cout << endl;
}
void PushStack(LinkStack& S, int data)
{
LinkStack p = new StackNode;
p->data = data;
p->next = S->next;
S->next = p;
}
void InitStack(LinkStack& S)
{
time_t t;
srand((unsigned)time(&t));
S->next = NULL;
int x = 0;
cout << “Possessing in PushStack:” << endl;
for (int i = 0; i < 10; i++)
{
x = rand() % (1000 - 100) + 100;
cout << "Top’s value is " << x << endl;
PushStack(S, x);
}
CoutStack(S);
cout << endl;
}
void PopStack(LinkStack& S, int& data)
{
if (S->next == NULL)
{
return;
}
LinkStack p = S->next;
data = p->data;
S->next = p->next;
delete p;
}
void Pop(LinkStack& S)
{
if (S->next == NULL)
{
cout << “Stack is Empty” << endl;
}
int x = 0;
cout << “Possessing in PopStack:” << endl;
while (S->next != NULL)
{
PopStack(S, x);
cout << "Top’s value is " << x << endl;
}
cout << endl;
}
int main()
{
LinkStack S = new StackNode;
InitStack(S);
Pop(S);
delete S;
}
程序运行结果:

调用过程:
1.初始时:

3、队列的链式存储结构的实现
(1)用随机函数生成10个3位整数(100~999),把这些整数应用入队操作存于队列中;
(2)应用遍历操作输出队列的内容;
(3)把队列的内容翻转,应用出队操作输出队列的内容。
代码部分:
#include
#include
using namespace std;
typedef struct ListNode
{
int data;
struct ListNode* next;
}ListNode;
typedef struct DataNode
{
int data;
struct DataNode* next;
}DataNode;
typedef struct
{
DataNode* front;
DataNode* rear;
}QueueNode;
void TraversalQ(QueueNode* Q)
{
if (Q->rear == NULL)
{
return;
}
DataNode* p = Q->front;
while (p != NULL && p->next != NULL)
{
cout << p->data << “->”;
p = p->next;
}
if (p != NULL)
{
cout << p->data << “->NULL”;
}
cout << endl;
}
void EnQueue(QueueNode*& Q,int data)
{
DataNode* S = new DataNode;
S->data = data;
if (Q->rear == NULL)
{
Q->front = Q->rear = S;
}
else
{
Q->rear->next = S;
Q->rear = S;
Q->rear->next = NULL;
}
}
void InitQueue(QueueNode*& Q)
{
Q->front = Q->rear = NULL;
for (int i = 0; i < 10; i++)
{
int x = rand() % 900 + 100;
EnQueue(Q, x);
cout << “Element of EnQueue:” << x << endl;
}
cout << “Queue:” << endl;
TraversalQ(Q);
}
void DeQueue(QueueNode*& Q, int& data)
{
if (Q->front == NULL)
{
cout << “Queue is Empty” << endl;
}
DataNode* p = Q->front;
if (Q->front == Q->rear)
{
Q->front = Q->rear = NULL;
}
else
{
Q->front = p->next;
}
data = p->data;
delete p;
}
void DeAllQueue(QueueNode*& Q)
{
if (Q->front == NULL)
{
return;
}
int data = 0;
while (Q->front != NULL)
{
DeQueue(Q, data);
cout << “Element of DeQueue:” << data << endl;
}
cout << endl;
}
void Push(ListNode*& S, int data)
{
ListNode* s = new ListNode;
s->data = data;
s->next = S->next;
S->next = s;
}
void Pop(ListNode*& S, int& data)
{
if (S->next == NULL)
{
return;
}
ListNode* p = S->next;
data = p->data;
S->next = p->next;
delete p;
}
void ReverseQueue(QueueNode*& Q)
{
ListNode* t = new ListNode;
t->next = NULL;
int x = 0;
while (Q->front != Q->rear) {
DeQueue(Q, x);
Push(t, x);
}

while (t->next != NULL) {
	Pop(t, x);
	EnQueue(Q, x);
}
cout << "After Reverse:" << endl;
TraversalQ(Q);

}
int main()
{
QueueNode* Q = new QueueNode;
InitQueue(Q);
ReverseQueue(Q);
DeAllQueue(Q);
delete Q;
}
程序运行结果:

4、线性表、栈和队列的应用实现:
(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
代码部分:
1.直接用冒泡排序法
#include
#include
using namespace std;
typedef struct LNode
{
int data;
struct LNode* next;
}LNode,*LinkList;
void CreateList_L(LinkList& L, int n)//前插法插入链表
{
L = new LNode;
L->next = NULL;
time_t t;
srand((unsigned)time(&t));
for (int i = n; i > 0; i–)
{
LinkList p = new LNode;
int rand_data = rand() % (1000 - 100) + 100;
p->data = rand_data;
p->next = L->next;
L->next = p;
}
}
void ListPrint(LinkList L)
{
cout << “Output the LinkList:” << endl;
LinkList p = L->next;
if (p == NULL)
{
cout << “The List is Empty!” << endl;
}
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
}
void LinkSort(LinkList &L)
{
cout << “After Sorting:” << endl;
int i;
for (i = 0; i < 9; i++)
{
LinkList p = L->next;
for (int j = 0; j < 9 - i ; j++)
{
if (p->data > p->next->data)
{
int e = p->data;
p->data = p->next->data;
p->next->data = e;
}
p = p->next;
}
}
ListPrint(L);
}
int main()
{
LinkList L;
CreateList_L(L, 10);
ListPrint(L);
cout << endl;
LinkSort(L);
}
程序实验结果:

2.两个指针
代码部分:
#include
#include
using namespace std;
typedef struct LNode
{
int data;
struct LNode* next;
}LNode,*LinkList;
void CreateList_L(LinkList& L, int n)//前插法插入链表
{
L = new LNode;
L->next = NULL;
time_t t;
srand((unsigned)time(&t));
for (int i = n; i > 0; i–)
{
LinkList p = new LNode;
int rand_data = rand() % (1000 - 100) + 100;
p->data = rand_data;
p->next = L->next;
L->next = p;
}
}
void ListPrint(LinkList L)
{
cout << “Output the LinkList:” << endl;
LinkList p = L->next;
if (p == NULL)
{
cout << “The List is Empty!” << endl;
}
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
}
void LinkSort(LinkList &L,int i)
{
cout << “After Sorting:” << endl;
for (int b = 0; b < 9; b++)
{
LinkList p = L->next;
while (p != NULL)
{
if (p->data >= i)
{
LinkList q = p;
while (q != NULL)
{
int e = q->data;//暂存结点q的数据
if (q->data < i)
{
q->data = p->data;
p->data = e;
break;
}
q = q->next;
}
}
p = p->next;
}
}
ListPrint(L);
}
int main()
{
LinkList L;
CreateList_L(L, 10);
ListPrint(L);
cout << endl;
int i;
cout << “Please Input a Integer:”;
cin >> i;
LinkSort(L,i);
}

程序实验结果:

(2)假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“…[…{…}…[…]…]…(…)” 为合法嵌套,“…[…{… )…[…]…]…(…)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。

  代码部分:
  #include<iostream>

using namespace std;
typedef struct StackNode
{
char c;
struct StackNode* next;
}StackNode,*LinkStack;
void InitStack(LinkStack& S)
{
S = NULL;
}
void Push(LinkStack& S, char c)
{
LinkStack p = new StackNode;
p->c = c;
p->next = S;
S = p;
}
void Pop(LinkStack& S)
{
if (S == NULL)
{
return;
}
LinkStack p = S;
S = S->next;
delete p;
}
char GetTop(LinkStack S)
{
if (S != NULL)
{
return S->c;
}
}
int StackEmpty(LinkStack S)
{
if (S == NULL)
{
return 1;
}
else
{
return 0;
}
}
int Matching()
{
LinkStack S;
InitStack(S);
int flag = 1;
char ch;
cout << “Please Input a string of brackets ,End with ‘#’” << endl;
cin >> ch;
while (ch != ‘#’ && flag)
{
switch (ch)
{
case’{’:
case’[’:
case’(’:
Push(S, ch);
break;
case’)’:
if (StackEmpty(S) == 0 && GetTop(S) == ‘(’)
{
Pop(S);
}
else
{
flag = 0;
}
break;
case’]’:
if (StackEmpty(S) == 0 && GetTop(S) == ‘[’)
{
Pop(S);
}
else
{
flag = 0;
}
break;
case’}’:
if (StackEmpty(S) == 0 && GetTop(S) == ‘{’)
{
Pop(S);
}
else
{
flag = 0;
}
break;
}
cin >> ch;
}
if (StackEmpty(S) == 1 && flag == 1)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
while (true)
{
if (Matching() == 0)
{
cout << “Matching False!” << endl;
cout << endl;
}
else
{
cout << “Matching Success!” << endl;
cout << endl;
}
}
}

程序运行结果:

(3)用队列求解迷宫问题的最短路径
代码部分:
#include
#include
using namespace std;
const int max1 = 6;
bool vst[max1][max1]; // 访问标记
int direction_vector[4][2] = { 0,1,0,-1,1,0,-1,0 }; // 方向向量 右,左,上,下
int maze[max1][max1];
int prior[max1][max1];//记录上一步的方向向量

struct State // BFS 队列中的状态数据结构
{
int x, y; // 坐标位置
int Step_Counter; // 搜索步数统计器
};

State t;

bool CheckState(State s) // 约束条件检验
{
if (!vst[s.x][s.y] && s.x >= 0 && s.x < 5 && s.y >= 0 && s.y < 5) // 满足条件
{
return 1;
}
else
{
return 0;
}
}

void BFS(State st)
{
State a[30];
queue q; // BFS 队列
State now, next; // 定义2 个状态,当前和下一个
st.Step_Counter = 0; // 计数器清零
q.push(st); // 入队
vst[st.x][st.y] = 1; // 访问标记
int k = 0, i, j;
while (!q.empty())
{
now = q.front(); // 取队首元素进行扩展
if (now.x == 4 && now.y == 4) // 出现目标态,此时为Step_Counter 的最小值,可以退出即可
{
cout << "The total of the journey is " << now.Step_Counter << endl; // 做相关处理
a[k++] = now;
next = now;
while (1)
{
switch (prior[now.x][now.y])
{
case 0:
next.y = now.y - 1;
break;
case 1:
next.y = now.y + 1;
break;
case 2:
next.x = now.x - 1;
break;
case 3:
next.x = now.x + 1;
}
a[k++] = next;
now = next;
if (next.x == 0 && next.y == 0)
break;
}
k–;
while (k >= 0)
{
cout << a[k].x << " " << a[k].y << endl;
k–;
}
return;
}
for (int i = 0; i < 4; i++)
{
next.x = now.x + direction_vector[i][0]; // 按照规则生成 下一个状态
next.y = now.y + direction_vector[i][1];
next.Step_Counter = now.Step_Counter + 1; // 计数器加1
if (CheckState(next)) // 如果状态满足约束条件则入队
{
prior[next.x][next.y] = i;
q.push(next);
vst[next.x][next.y] = 1; //访问标记
}
}
q.pop(); // 队首元素出队
}
return;
}

int main()
{
cout << “Please Input 5*5 Two-dimensional array:” << endl;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
cin >> maze[i][j];
if (maze[i][j] == 1)
{
vst[i][j] = true;
}
}
t.x = 0;
t.y = 0;
BFS(t);
}
程序运行结果:

<代码/程序执行结果/操作结果>
五、实验结果及分析
<逐条列出代码编写过程中出现的错误,及改正的方案>
1.线性表的链表实现
问题1.
生成随机函数时,没加上srand()初始化随机数发生器,会发现rand()虽然产生了随机数,但是重复运行会发现随机数不会变。查看后发现rand()产生的是伪随机数字,每次执行是相同的。
问题2.
直接对链表进行翻转,不开辟新空间用来保存结点,只能改变指针的指向,我就利用前面前插法创建链表的思想,将结点依次插到头结点的后面。因为先插入的结点为表尾,后插入的结点为表头,可实现链表的翻转。
利用原有的头结点L,p为工作指针,初始时p指向首元结点。因为摘取的结点依次向前插入,为确保链表尾部为空,初始时应将头结点的指针域置为空。然后从前向后遍历链表,依次摘取结点,在摘取结点前,需要用指针q记录后置结点,以防止链接后丢失后继结点,之后将摘取的结点插入到头结点的后面,最终p指向新的结点
如下图所示:

3、队列的链式存储结构的实现
1.刚开始不知道遍历是什么意思,以为只是输出某些数据。后来知道就是从队列头创造一个新指针开始进行遍历,从前往后走一遍,当执行p=p->next时,就输出p->data即可,一直走到表尾即可。
问题3.翻转队列时,由于考虑到不破坏队列的性质,因此采用队列和堆栈结合的情况操作,通过将队列原有的元素出队列,进栈和出栈,重新进队列来实现翻转。
具体实现过程:
创建一个新结点,当队列不为空时,每个元素逐渐退出队列,并将其压入栈中,直至对列为空。然后弹出栈,并进入队列,直至栈为空,便实现了队列翻转.

4、线性表、栈和队列的应用实现:
(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
思路:
刚开始只想到第一点:
1.用冒泡排序法从小到大排列一遍即可,不管它即将要插入的数据是谁,小的一定在大的后面
2.用两个指针跟踪链表,从首元结点开始,p,q同时指向L->next;当p非空且大于该读入的整数,q指向p,去遍历q,直到找到小于该整数,找到后,p,q数值互换,p继续遍历,直到p->next==NULL为止。
问题四: 创造顺序表时,
结果是:只有9个数据,后来发现我的InsertList函数的置数出现问题,导致第九个数据的指针域置空,应该把第i个数据元素L.elem[i-1]赋给参数e,而我的函数就把它赋值给L.elem[i]了。
问题5:调用排序法时:
运行时:
它最终结果与没排序前原先是一样的,我就检查了一下引用符号,发现我已经加了,这个问题仍未解决,就只能用我大一上学过的简单的冒泡排序法来做了

(3)用队列求解迷宫问题的最短路径
思路:这个迷宫问题不是难在BFS寻找最短步数中,而是难在怎么去记录他的正确走法的坐标。
最后,我查了CSDN,要多开一个5*5的数组,来记录每一个坐标上一步是什么。这里可以记录上一步到这里的方向向量,也可以直接记录上一步的坐标。当BFS寻找到右下角的点的时候,从最后一个点开始向上通过这个数组往回推,得到一系列坐标,可以存放在栈中,也可以直接放在一个数组中,最后输出这些坐标就可以了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值