实验一 线性表、堆栈和队列的操作与实现

开课实验室:计算机科学与工程实验(电子楼)       20201122

学院

计算机科学与网络工程学院

年级、专业、班

网络工程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. 广州大学 数据结构实验报告

    数据结构 实验一 一.实验目的: 1.线性表的链表实现:遍历.查找.插入.删除.翻转 2.栈的链式存储结构实现:入栈.出栈 3.队列的链式存储结构的实现:入队.出队 4.线性表.栈和队列的应用实现 二 ...

  2. 广州大学数据结构实验四

    实验四 查找和排序算法实现 开课实验室:计算机科学与工程实验(电子楼)       2020年12月31日 学院 计算机科学与网络工程学院 年级.专业.班 网络工程194 姓名 jwt 学号 实验课程 ...

  3. 广州大学学生实验报告,数据结构实验,二叉树的操作与实现

    广州大学学生实验报告 开课学院及实验室: 计算机科学与工程实验室 418              2022年10月3日 学院 计算机科学与网络工程 年级.专业.班 计科 姓名 Great Macro ...

  4. 数据结构实验六 综合数据处理

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416A)     2019年6月14日 学院 计算机科学与教育软件学院 年级.专业.班 计算机大类 144班 姓名 学号 实验课程名称 ...

  5. 数据结构实验五 查找算法的实现

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416B)     2019年6月11日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实 ...

  6. 数据结构实验四 排序算法的实现

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416)     2019年6月4日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实验项 ...

  7. 数据结构实验三 树的遍历生成树

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A)     2019年4月19日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术 姓名 学号 实验课程名称 数据 ...

  8. 数据结构实验二 树和二叉树的实现

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A)     2019年5月13日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术172班 姓名 学号 17061 ...

  9. 数据结构-实验二  树和二叉树的实现

     广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼417)     2018年05月16日 学院 计算机科学与教育软件学院 年级.专业.班 网络161 姓名 卟咚君 学号 1606100 ...

最新文章

  1. c++ 三次多项式拟合_非线性回归模型(一)--多项式回归
  2. python资料免费-MicroPython最全资料免费获取
  3. 10.31NOIP模拟赛解题报告
  4. remote vscode无git_vs code 使用git
  5. 高并发处理方案_高并发系统下的缓存解决方案
  6. clone git 要输入yes_GitHub,git与python连接使用
  7. No project is easy, am I right?
  8. 解决Eclipse发布到Tomcat丢失依赖jar包的问题
  9. 层次分析法详细讲解(小白必看电脑查看)
  10. 卸载软件时,出现解压缩支持文件时出错,灾难性故障--转载
  11. 数据结构(一)线性链表、非线性链表、稀疏数组与队列、单向链表
  12. 南京大学计算机专业复试面试,南大计算机面试问题汇总及部分答案.doc
  13. 分类问题中的几个衡量指标
  14. java计算机毕业设计英语课程学习网站源程序+mysql+系统+lw文档+远程调试
  15. JQuery解析Json数据填充到表格
  16. 分享知识-快乐自己:oracle12c创建用户提示ORA-65096:公用用户名或角色无效
  17. 【论文笔记】:CornerNet: Detecting Objects as Paired Keypoints
  18. 电子合同可以被打印出来吗
  19. flex 教程_完整的flex教程
  20. 分享99个PHP留言日记源码,总有一款适合您

热门文章

  1. 知数堂全网通缉这个人
  2. iOS 面试基础题目
  3. 如何让HTML字体变的更小
  4. 《速通深度学习数学基础》
  5. 企业绩效管理怎么做?
  6. 计算机硬件及编程语言
  7. ROS-Ardunio 点亮LED灯
  8. 鼠标指针(光标)变成黑方块的解决方法
  9. 在纽约寻找童真——新泽西州乐高乐园探索中心的美好一天
  10. 富士胶片3月底完成日立影像诊断业务收购;中国癌症早筛第一股诺辉健康登陆港交所 | 美通企业日报...