广州大学数据结构实验一
实验一 线性表、堆栈和队列的操作与实现
开课实验室:计算机科学与工程实验(电子楼) 2020年11月22日
学院 |
计算机科学与网络工程学院 |
年级、专业、班 |
网络工程194 |
姓名 |
jwt |
学号 |
||
实验课程 |
数据结构实验 |
成绩 |
||||||
实验项目 |
实验一 线性表、堆栈和队列的操作与实现 |
指导老师 |
|
一、实验目的
1、线性表的链表实现:遍历、查找、插入、删除、翻转
2、栈的链式存储结构实现:入栈、出栈
3、队列的链式存储结构的实现:入队、出队
4、线性表、栈和队列的应用实现
二、使用仪器、器材
操作系统:Win10
编程软件:C++
三、实验内容及原理
1、线性表的链表实现
(1) 用随机函数生成10个3位整数(100~999),把这些整数存于链表中;
思路:首先调用initList(List &L)初始化链表,然后用后插法创建链表,数据域赋予随机数,随机数通过srand((unsigned)time(NULL))确定,并规定范围为rand()%900+100即100-999。
(2) 输出链表的内容;
思路:定义指针p指向首元结点,然后向后扫描,逐个数据域输出。
(3) 读入一个整数,查看该整数是否在表中,若在,输出其位置(首位置为1);思路:定义指针p指向首元结点,然后向后扫描,当找到与之相同的数据域时,返回下标。
(4) 读入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容(要求判断输入的位置是否合理);
思路:定义指针p指向首元结点,然后向后扫描,到达相应位置后,建立一个新结点,新结点指针域储存要插入结点的指针域,然后插入该结点后
(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),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。
思路:创建两个新链表,一个用于储存比该数小的数据,一个用于储存比该数大的数据,最后合并两个链表。
(2) 假设一个字符串中可以包含三种括号:( )[ ]{},且这三种括号可以按任意次序嵌套使用(如:“...[...{...}...[...]...]...(...)” 为合法嵌套,“...[...{... )...[...]...]...(...)”为不合法嵌套)。编写判别给定表达式中所含括号是否正确配对出现的算法,如果是合法嵌套则返回为true,如果是不符合法嵌套则返回为false。
思路:运用链栈可以解决,当读取到左括号时,把左括号压入栈,当读取到右括号时判断栈顶是否有相应的左括号与之匹配,若有,则栈顶元素出栈,循环下去即可解决。
(3) 用队列求解迷宫问题的最短路径
思路:
1.从起点开始,将其加入队列,设置距离为0;
2.从队列首端取出位置,将从这个位置能够到达的位置加入队列,并且让这些位置的距离为上一个位置的距离加上1;
3.一轮探索至无法继续向队列中添加元素,即当前所在点的四周情况全部考虑完成后,循环第二步,直到将终点添加到队列中。说明此时已经找到了路径;
4.求出并存储各条路径,并比较得出最短路径
四、源码及结果分析
一、线性表的链表实现
//1.
void inputList(List &L) //输入随机数,后插法创建链表
{List p, r;//p用于生成新结点,r为尾指针r = L;//尾指针初始化,指向头结点srand((unsigned)time(NULL));//随机数种子for (int i=0; i < 10; i++){p = new LNode;//生成一个新结点pp->data = rand() % 900 + 100;//输入元素值赋给*p的数据域p->next = NULL;r->next = p;//将新结点插入尾结点r = p;//更新尾指针,指向新结点*p}cout << "创建成功" << endl;
}//2.
void outputList(List L) //输出链表元素
{List p;p = L->next;//p指向首元结点while (p!=NULL)//p向后扫描,直到p为空{cout << p->data << " ";//输出p的数据域p = p->next;//p指向下一个节点}cout << endl;
}//3.
int locateList(List L, int num) //判断链表中是否存在该元素,若有则返回相应下标
{List p=NULL;p = L->next;//p指向首元结点int temp = 1;// 首位置为1while (p != NULL)//p向后扫描,直到p为空{if (p->data == num)//查找成功return temp;//返回相应元素的下标temp++;p = p->next;//p指向下一个节点}return -1;//找不到元素,返回-1
}//4.
void insertList(List &L, int num,unsigned int index) //插入元素至链表指定位置,num为插入的元素,index为插入的位置
{List p = L;int j = 1;// 首位置为1while (p && (j < index))//p非空且初始位置小于要插入的指定位置时,向后扫描{p = p->next;j++;}if (!p && (j>index))//index大于链表长度或index<1{cout << "插入失败!" << endl;return;}else{List r = NULL;r = new LNode;//生成新结点r->data = num;//将*r的数据域置为numr->next = p->next;//新结点保存原来结点的下一指向p->next = r;//要插入位置的指针域指向新结点cout << "插入成功!" << endl;}cout << "插入新元素后的链表为: ";outputList(L);//输出插入后的链表if (index != locateList(L, num))//判断是否插入指定位置cout << "未插入指定位置!" << endl;elsecout << "已插入指定位置!" << endl;
}//5.
void deleteList(List &L, int num) //删除链表节点
{int i=locateList(L, num);//判断链表中是否有该元素,若有,则返回相应下标if (i == -1){cout << "删除失败,链表中没有该元素!" << endl;return;}else{List p=L,q=NULL;int j = 1;while ((p->next) && (j < i))//查找第i-1个结点,p指向该结点{p = p->next;j++;}if ((!p->next) || (j>i))//当i>链表长度或者i<1时,删除位置不合理{cout << "删除位置不合理!" << endl;return;}else{q = new LNode;q = p->next;//q用于临时保存被删除结点的地址以备释放p->next = q->next;//改变删除节点前驱结点的指针域delete q;//释放删除结点的空间cout << "删除成功!" << endl;}}
}//6.
void flipList(List L)//因为创建时用了后插法,所以用前插法创建新链表即可实现翻转
{List p = NULL,r=NULL,h=NULL;initList(p);//初始化新链表r = L->next;while (r)//原链表向后扫描{h = new LNode;//生成新结点h->data = r->data;//新结点的数据域置为原链表首元结点的数据r = r->next;//向后扫描h->next = p->next;p->next = h;//新结点插入头结点后}outputList(p);//输出翻转后的链表
}
创建链表,并赋予10个随机数,然后输出链表,输入666后,选择插入的位置为3,再输出链表,可以看到666已经插在555之后排在第三位;然后删除666,输出删除后的链表,结果正确;最后调用翻转链表函数,翻转成功!
二、栈的链式存储结构实现
//1.
void inputStack(LinkStack &S)//链栈的入栈
{LinkStack p=NULL;srand((unsigned)time(NULL));//随机数种子for (int i = 0; i < 10; i++){p = new SNode;//生成新结点p->data = rand() % 900 + 100;//将数据域置为随机数100-999p->next = S;//将新结点插入栈顶S = p;//修改栈顶指针为p}cout << "入栈成功" << endl;
}
注:因为10个随机数调试太多,所以换成了2个随机数再进行调试
在入栈处设置断点1,先是955入栈,然后第二次循环到920入栈,栈顶元素变为了920
//2.
void popStack(LinkStack &S)//链栈的出栈
{while (S){cout << S->data << " ";//输出元素LinkStack p = S;//p临时保存栈顶元素空间,以备释放S = S->next;//更新栈顶指针delete p;//释放原栈顶元素空间}cout << endl;
}
初始时栈顶元素为920与上边一致,说明入栈操作正确,出栈时先释放920,下一步释放955,最后栈为空。
三、队列的链式存储结构的实现
//1.
void inputQueue(LinkQueue &Q) //创建队列
{QueuePtr p;srand((unsigned)time(NULL));for (int i = 0; i < 10; i++){p = new QNode; //为入队元素分配结点空间,用指针p指向p->data = rand()%900+100; //赋予随机数p->next = NULL;Q.rear->next = p; //将新结点插入到队尾Q.rear = p; //修改队尾指针}
}
//2.
void outputQueue(LinkQueue &Q)//输出队列内容
{QueuePtr p;p = Q.front->next;//p指向队头元素while (p)//向后扫描{cout << p->data << " ";p = p->next;}cout << endl;
}
//3.
void flipQueue(LinkQueue &Q)//翻转队列
{QueuePtr h = Q.front->next;//暂存队头空间QueuePtr r = Q.front->next;int count = countQueue(Q);//count用于储存队列长度,countQueue(Q)用于统计队列长度Q.front->next = Q.rear;//将队头元素置为队尾元素for (int i = 0; i < count; i++){while (r)//r非空时向后扫描{if (r->next == Q.rear)//找到队尾指针(r为倒数第二个结点){Q.rear->next = r;//队尾指针的指针域指向rQ.rear = r;//更新队尾指针break;}r = r->next;}r = h;//将队头空间赋予r,循环后达到翻转效果}r->next = NULL;//最后一个元素指针域置为空Q.rear = r;//更新队尾指针cout << "翻转后的队列为: ";outputQueue(Q);
}
先创建队列,并用outputQueue()输出原队列,然后调用翻转函数flipQueue(),翻转成功!
四、线性表、栈和队列的应用实现
//1.
List divideList(List L,int num)//分割链表
{List sh = NULL;//小链表头List st = NULL;//小链表尾List lh = NULL;//大链表头List lt = NULL;//大链表尾List p = L->next;//p指向原链表的首元结点while (p)//向后扫描{if (p->data < num)//若该结点的数据小于num{if (sh == NULL)//sh尚未初始化{initList(sh);sh->next = p;//把该结点插到sh之后st = sh->next;//更新尾指针st}else//若sh已经初始化,已有首元结点{st->next = p;//插入该结点st = st->next;//更新尾指针st}}else//若该结点的数据大于num{if (lh == NULL)//lh尚未初始化{initList(lh);lh->next = p;//把该结点插到lh之后lt = lh->next;//更新尾指针lt}else{lt->next = p;//插入该结点lt = lt->next;// 更新尾指针lt}}p = p->next;//指向下一结点}if (sh == NULL)//如果没有比num小的数,则小链表为空,返回大链表的头指针{return lh;}elsest->next = lh->next;//将大链表的首元结点插入小链表的尾部return sh;//返回小链表的头指针
}
如图,首先创建链表赋予10个随机数,然后输入300,结果分割后的链表显示为,小于300的3个数都在左边,大于300的7个数都在右边
//2.
bool matching()//括号匹配
{LinkStack S;initStack(S);//初始化链栈bool judge = true;//判断匹配结果,初始化为真char str[20];//字符数组存储算术表达式cout << "请输入括号组成的字符串: ";cin >> str;int length = strlen(str);//获取输入算术表达式的长度for (int i = 0; i < length; i++){switch (str[i])//根据符号的不同执行不同的操作{case '[':case '(':case '{'://读取到左括号时,将左括号压入栈pushStack(S, str[i]);break;case ']'://读取到右括号]{if (notEmptyStack(S) && getTop(S) == '[')//判断栈顶元素是否为对应的左括号{judge = true;popStack(S, str[i]);//若匹配,judge取真,栈顶元素出栈}elsejudge = false;//不匹配,judge取假break;}case ')'://读取到右括号){if (notEmptyStack(S) && getTop(S) == '(')//判断栈顶元素是否为对应的左括号{judge = true;popStack(S, str[i]);//若匹配,judge取真,栈顶元素出栈}elsejudge = false;//不匹配,judge取假break;}case '}'://读取到右括号}{if (notEmptyStack(S) && getTop(S) == '{')//判断栈顶元素是否为对应的左括号{judge = true;popStack(S, str[i]);//若匹配,judge取真,栈顶元素出栈}elsejudge = false;//不匹配,judge取假break;}default:break;}}if (!notEmptyStack(S) && judge)//如果栈空并且judge判断为真,则匹配成功return true;elsereturn false;
}
测试了两条表达式,第一条匹配失败,第二条匹配成功
//3.
typedef struct node
{int x, y; //横纵坐标int pre; //指向前驱点的坐标
}SqType;typedef struct
{int x, y;
}item;item assignMove(item moveEle[4])//向可移动的4个方向的移动后的坐标变化,从正右方顺时针开始
{for (int i = 0; i < 8; i++){switch (i){case 0:moveEle[0].x = 1; moveEle[0].y = 0; break;case 1:moveEle[1].x = 0; moveEle[1].y = 1; break;case 2:moveEle[2].x = -1; moveEle[2].y = 0; break;case 3:moveEle[3].x = 0; moveEle[3].y = -1; break;}}return moveEle[4];
}void printPath(SqType *sq,int count[])
{int min = 999;//假设最短路径长度为999int i = 0;int arr[10];//用于储存各路径到达终点路径长度for (int k = 0; k < 10; k++)//初始化各路径路径长度为0arr[k] = 0;for (int j = 0; j < 10; j++){if (count[j] != 0)//若有路径,则计算路径长度{i = count[j];while (i != -1){i = sq[i].pre;arr[j]++;//更新路径长度}}if (count[j] == 0)//没有路径则跳出循环break;}int length = 0;for (int j = 0; j < 10; j++)//找出最短路径{if ((arr[j] < min) && (arr[j] != 0)){min = count[j];//令min等于最短路径的rearlength = arr[j];}}while (min != -1)//打印路径{cout << sq[min].x << "," << sq[min].y << " " << endl;min = sq[min].pre;}cout << "最短路径长度为: " << length << endl;
}void set(int count[], int n)//储存步数
{for (int i = 0; i < 10; i++){if (count[i]== 0){count[i] = n;break;}}
}/*利用队列求最短路径*/
void path()
{ //*((int*)pia3 + i * 4 + j)item moveEle[4];moveEle[4] = assignMove(moveEle);//最外一圈建立“围墙”,防止数据溢出数组范围int maze[9][10] ={ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 0, 0, 0, 0, 0, 1, 0, 0, 1,1, 0, 1, 1, 1, 0, 0, 1, 0, 1,1, 0, 0, 1, 0, 1, 0, 0, 0, 1,1, 1, 0, 1, 0, 1, 1, 0, 1, 1,1, 0, 0, 1, 0, 0, 0, 0, 0, 1,1, 0, 1, 1, 0, 1, 1, 0, 1, 1,1, 0, 0, 0, 0, 0, 0, 0, 0, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };int n = 9, m = 10;//行数和列数SqType sq[num];//用于记录所经过的坐标int front, rear;//前驱、后继下标int x, y, i, j, v;//i,j分别对应新的横纵坐标sq[0].x = 1;sq[0].y = 1;//设置起点sq[0].pre = -1;//已经过的点标记为-1front = rear = 0;maze[1][1] = -1; //标记已经过的位置int count[10];//储存各路径的rearfor (int k = 0; k < 10; k++)count[k] = 0;while (front <= rear){//更新x,y的坐标x = sq[front].x;y = sq[front].y;for (v = 0; v<4; v++)//朝4各方向移动后的坐标变化{i = x + moveEle[v].x;j = y + moveEle[v].y;if (maze[j][i] == 0)//0表示通行,1表示没路走{rear++;//若可通行,步数+1//走下一步的坐标sq[rear].x = i;sq[rear].y = j;sq[rear].pre = front;//记录前驱maze[j][i] = -1;//已经过的点标记为-1}if ((i == m-2) && (j == n-2))//设置终点坐标set(count, rear);//储存步数}front++;}cout << "最短路径为: " << endl;printPath(sq, count);
}
因为输入迷宫太繁琐,所以直接定义了一个迷宫的二维数组。
通过执行path()来求解该迷宫的最短路径,并输出最短路径的行走经过以及最短路径的长度。
五、实验结果及分析
总结:1.遍历时要注意,创建的指针是指向头指针还是首元结点,不然可能会遍历不到最后一个元素提前结束,或者达不到想要的效果。
2.插入功能应该先要判断插入位置是否合理,否则可能输出乱码
3.链表合并时,应插入第二个链表的首元结点,如果插入的是头指针,会输出一堆数字。
4.括号匹配时,一定要认真看左右括号是否输入对,否则编译器不会提示你错误,要找半天。。。
5.某些程序出bug时,可以设置断点,逐条语句运行找到问题所在。
实验结果:实验结果基本都运行正确(即截屏所示)。
改进:在执行栈的操作时,应该先写一个函数判断是否为空栈。队列链表类似。
Pass:仅作为实验参考,有些地方可能不够完善,见谅一下。转载请注明出处!
广州大学数据结构实验一相关推荐
- 广州大学 数据结构实验报告
数据结构 实验一 一.实验目的: 1.线性表的链表实现:遍历.查找.插入.删除.翻转 2.栈的链式存储结构实现:入栈.出栈 3.队列的链式存储结构的实现:入队.出队 4.线性表.栈和队列的应用实现 二 ...
- 广州大学数据结构实验四
实验四 查找和排序算法实现 开课实验室:计算机科学与工程实验(电子楼) 2020年12月31日 学院 计算机科学与网络工程学院 年级.专业.班 网络工程194 姓名 jwt 学号 实验课程 ...
- 广州大学学生实验报告,数据结构实验,二叉树的操作与实现
广州大学学生实验报告 开课学院及实验室: 计算机科学与工程实验室 418 2022年10月3日 学院 计算机科学与网络工程 年级.专业.班 计科 姓名 Great Macro ...
- 数据结构实验六 综合数据处理
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416A) 2019年6月14日 学院 计算机科学与教育软件学院 年级.专业.班 计算机大类 144班 姓名 学号 实验课程名称 ...
- 数据结构实验五 查找算法的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416B) 2019年6月11日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实 ...
- 数据结构实验四 排序算法的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416) 2019年6月4日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实验项 ...
- 数据结构实验三 树的遍历生成树
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A) 2019年4月19日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术 姓名 学号 实验课程名称 数据 ...
- 数据结构实验二 树和二叉树的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A) 2019年5月13日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术172班 姓名 学号 17061 ...
- 数据结构-实验二 树和二叉树的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼417) 2018年05月16日 学院 计算机科学与教育软件学院 年级.专业.班 网络161 姓名 卟咚君 学号 1606100 ...
最新文章
- c++ 三次多项式拟合_非线性回归模型(一)--多项式回归
- python资料免费-MicroPython最全资料免费获取
- 10.31NOIP模拟赛解题报告
- remote vscode无git_vs code 使用git
- 高并发处理方案_高并发系统下的缓存解决方案
- clone git 要输入yes_GitHub,git与python连接使用
- No project is easy, am I right?
- 解决Eclipse发布到Tomcat丢失依赖jar包的问题
- 层次分析法详细讲解(小白必看电脑查看)
- 卸载软件时,出现解压缩支持文件时出错,灾难性故障--转载
- 数据结构(一)线性链表、非线性链表、稀疏数组与队列、单向链表
- 南京大学计算机专业复试面试,南大计算机面试问题汇总及部分答案.doc
- 分类问题中的几个衡量指标
- java计算机毕业设计英语课程学习网站源程序+mysql+系统+lw文档+远程调试
- JQuery解析Json数据填充到表格
- 分享知识-快乐自己:oracle12c创建用户提示ORA-65096:公用用户名或角色无效
- 【论文笔记】:CornerNet: Detecting Objects as Paired Keypoints
- 电子合同可以被打印出来吗
- flex 教程_完整的flex教程
- 分享99个PHP留言日记源码,总有一款适合您