广州大学数据结构实验一

广州大学学生实验报告

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

学院

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

年级、专业、班

姓名

学号

实验课程

数据结构实验

成绩

实验项目

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

指导老师

评语:

一、实验目的

1、线性表的链表实现:遍历、查找、插入、删除、翻转

2、栈的链式存储结构实现:入栈、出栈

3、队列的链式存储结构的实现:入队、出队

4、线性表、栈和队列的应用实现

二、使用仪器、器材

微机一台

操作系统:WinXP

编程软件:C++

三、实验内容及原理

填入自己的内容(思路或算法流程图、源代码、说明等)

1、线性表的链表实现:

(1)用随机函数生成10个3位整数(100~999),把这些整数存于链表中;

(2)输出链表的内容;

(3)读入一个整数,查看该整数是否在表中,若在,输出其位置(首位置为1);

(4)读入一个整数,以及要插入的位置,把该整数插入到链表中,输出链表的内容(要求判断输入的位置是否合理);

(5)读入一个整数,若该整数在链表里,删除该整数,输出链表的内容;

(6)把链表的内容翻转,输出链表的内容。

#include<stdio.h>

#include<stdlib.h>

#include "time.h"//用到时间函数

#include "math.h"//用到随机函数

#define ERROR -1

#define OK 1

//定义

typedef struct Lnode

{

int data;

Lnode* next;

}Lnode, * LinkList;

//初始化

int InitList_L(LinkList& L)

{

//L = (LinkList)malloc(sizeof(Lnode));

L = new Lnode();//将结点的地址赋值给L,即L指向头结点

L->next = NULL;//L的指针域置空

return OK;

}

//输出链表

void PrintList(LinkList& L)

{

Lnode* p = L->next;

printf("Output the list: ");

while (p != NULL)//遍历链表并输出

{

printf("%d ", p->data);

p = p->next;

}

printf("\n");

}

//获取表长

int ListLength(LinkList& L)

{

LinkList p;

p = L->next;//p指向首元结点

int i = 0;

while (p)

{

i++;

p = p->next;

}

return i;

}

//查找,获取该数据的位置序号

void LocateElem_L(LinkList& L, int e)

{

Lnode* p;

p = L->next; int place = 1;

while (p && p->data != e)

{

p = p->next; place++;

}

if (p) printf("The location is %d\n", place);

else printf("The integer is not in the List\n");

}

//插入

void InsertElem_L(LinkList L, int place, int num)

{

Lnode* p = L; int j = 1;

while (p && (j != place))//p指向第i个结点

{

p = p->next; ++j;

}

if (!p || j < place)

{

printf("Insert failed!\n");

}

else

{

Lnode* s = new Lnode();

s->data = num;//生成新的结点s,并将*s的数据域置为e

s->next = p->next;//将结点s插入L中

p->next = s;

}

int n = ListLength(L);

PrintList(L);

}

//尾插法

void CreateList_L(LinkList& L, int n)

{

L = new Lnode; L->next = NULL;

LinkList r = L;//尾指针指向头结点

for (int i = 1; i <= n; i++)

{

LinkList p = new Lnode; //生成新结点,输入元素值

p->data = rand() % 900 + 100;

p->next = NULL;

r->next = p;//插入到表尾

r = p;//r指向新的尾结点

}

}

//删除

/*int ListDelete_L(LinkList& L, int place, int& num)

{

LinkList p = L; int delplace = 0;//定义一个位置delplace,用于判断要删除的位置place是否合理

while (p->next && delplace < place - 1) { p = p->next; delplace++; }

if (!(p->next) || delplace > place - 1)return ERROR;

LinkList q = p->next;//临时保存被删除结点的地址已备释放

p->next = q->next;//改变删除结点前驱结点的指针域

num = q->data;//保存删除结点的指针域

delete q;//释放删除结点的空间

return OK;

}*/

void ListDelete_num(LinkList& L, int n, int num)

{

Lnode* p = L; int pla = 1;

while (p->next && num != p->next->data)//若输入整数与p指向的元素的下一个元素不相等,将p指向下一个元素

{

p = p->next;

pla++;

}

if (pla <= n)//删除p

{

LinkList q = p->next;//临时保存被删除结点的地址已备释放

p->next = q->next;//改变删除结点前驱结点的指针域

num = q->data;//保存删除结点的指针域

delete q;//释放删除结点的空间

}

else

printf("Deleted failed!\n");

PrintList(L);

}

//翻转链表

void ListReverse(LinkList& L)//翻转后输出链表所有数据

{

Lnode* p = L->next;

Lnode* temp;

InitList_L(temp);

while (p != NULL)

{

Lnode* q = p->next;

p->next = temp->next;

temp->next = p;

p = q;

}

L = temp;

printf("Output the reverselist:\n");

    PrintList(L);//输出链表翻转后的数据

}

int main()

{

LinkList L;

int n = 10,num = 0, num1, num2, num3, num4;//n为链表长度,num为输入整数

srand((unsigned int)time(NULL));

InitList_L(L);//初始化链表,让L指向头结点

CreateList_L(L, n);//使用尾插法生成链表

PrintList(L);//输出链表

printf("Please input an integer that you want to find:");

scanf_s("%d", &num1);

LocateElem_L(L, num1);//输出查找元素的位置

printf("Please input an integer and its location:");

scanf_s("%d%d", &num2, &num3);  //输入异常

InsertElem_L(L, num3, num2);

printf("Please input an integer:");

scanf_s("%d", &num4);

ListDelete_num(L, n, num4);

ListReverse(L);

}

2、栈的链式存储结构实现

(1)用随机函数生成10个3位整数(100~999),把这些整数应用入栈操作存于堆栈中,在入栈接口处设置断点①,按“F5”启动调试,按“F10”逐句执行,直到数据全部入栈。程序暂停时观察栈顶数据和栈顶位置;

(2)应用出栈操作输出堆栈的内容,在出栈接口处设置断点②,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈,程序暂停时观察栈顶数据和栈顶位置的变化; 

#include<stdio.h>

#include<stdlib.h>

#include<cmath>

#include<time.h>

#define OK 1;

#define ERROR 0;

//定义

typedef struct LNode {

int data;

struct LNode* next;

}LNode, * LinkStack;

//初始化链

int InitStack(LinkStack& S) {

S = NULL;

return OK;

}

//入栈

int PushStack(LinkStack& S) {

LNode* p = new LNode;

p->data = rand() % 900 + 100;

p->next = S;

S = p;

printf("%d进栈\n", S->data);

return OK;

}

//出栈

int PopStack(LinkStack& S) {

if (S == NULL) return ERROR;

LNode* p = S;

printf("%d已出栈\n", S->data);

S = S->next;

delete p;

return OK;

}

int main()

{

LinkStack S;

srand((int)time(0));

for (int i = 0; i < 10; i++)

{

PushStack(S);

}

for (int i = 0; i < 10; i++)

{

PopStack(S);

}

}

3、队列的链式存储结构的实现

(1)用随机函数生成10个3位整数(100~999),把这些整数应用入队操作存于队列中;

(2)应用遍历操作输出队列的内容;

(3)把队列的内容翻转,应用出队操作输出队列的内容。

#include <stdio.h>

#include<stdlib.h>

#include "time.h"

#include "math.h"

struct LinkQueue

{

    int data;

    LinkQueue* next;

};

struct LinkQueuePtr

{

    LinkQueue* front;//队首头结点

    LinkQueue* rear;//队尾

};

void InitQueue(LinkQueuePtr& q)//初始化队列指针

{

    q.front = new LinkQueue;

    q.rear = q.front;

    q.front->next = NULL;

}

void PushQueue(LinkQueuePtr& q, int data)//数据压入队尾

{

    LinkQueue* tmp = new LinkQueue;

    tmp->data = data;

    tmp->next = NULL;//新建一个队列指针

    q.rear->next = tmp;//将队尾的next连接到添加节点

    q.rear = q.rear->next;//队尾移到新添加节点

}

int PopQueue(LinkQueuePtr& q)//弹出队首元素并返回值

{

    if (q.front == q.rear) { printf("队列为空"); return -1; }//队列为空

    LinkQueue* tmp = q.front->next;

    int data = tmp->data;

    q.front->next = tmp->next;//将队列头结点指向下一个结点

    if (q.rear == tmp) q.rear = q.front;//如果删除的为最后一个结点,队列空,队尾置为队首

    free(tmp);

    return data;

}

void ReverseQueue(LinkQueuePtr& q)

{

    LinkQueue* m = q.front->next;//暂存原队列首元素空间

    LinkQueue* move = q.front->next;

    q.front->next = q.rear;//将首元素替换成末尾元素

    for (int i = 0; i < 10; i++)

    {

        while (move)

        {

            if (move->next == q.rear)

            {

                q.rear->next = move;

                q.rear = move;

                break;

            }

            move = move->next;

        }

        move = m;

    }

    move->next = NULL;//最后一个元素的指针域置空

    q.rear = move;

}

int main()

{

    srand(unsigned int(time(0)));

    LinkQueuePtr q;//创建队列指针

    InitQueue(q);//初始化队列

    for (int i = 0; i < 10; i++)

    {//生成随机数并压入队列

        int data = rand() % 900 + 100;

        PushQueue(q, data);

    }

    printf("队列的遍历数据如下\n");

    for (int i = 0; i < 10; i++)//遍历队列所有数据

    {

        int data = PopQueue(q);

        printf("%d ", data);

        PushQueue(q,data);

    }

    printf("\n");

    ReverseQueue(q);

    printf("队列翻转后输出内容\n");

    for (int i = 0; i < 10; i++)//遍历输出数据

    {

        printf("%d ", PopQueue(q));

    }

}

4、线性表、栈和队列的应用实现:

(1)用随机函数生成10个3位整数(100~999),把这些整数存于单链表中,然后读入一个整数,以该值为基准把单链表分割为两部分,所有小于该值的结点排在大于或等于该值的结点之前。

#include<stdio.h>

#include<stdlib.h>

#include "time.h"

#include "math.h"

#define OK 1

#define ERROR 0

typedef struct LNode {

int data;

struct LNode* next;

LNode* Rear;

}LNode, * LinkList;

//创建空表

int InitList(LinkList& L)

{

L = new LNode;

L->next = NULL;

L->Rear = L;

return OK;

}

//链表的存储

int StoreElem(LinkList& L, int& e)

{

LNode* p = new LNode;

p->data = e;

p->next = NULL;

L->Rear->next = p;

L->Rear = p;

return OK;

}

// 输出链表内容

int ShowElem(LinkList& L)

{

LNode* p = L->next;

printf("链表输出:\n");

while(p)

{

printf("%d ", p->data);

p = p->next;

}

printf("\n");

return OK;

}

int CreateList(LinkList& L)

{

for (int i = 0; i < 10; ++i)

{

int j = rand() % 900 + 100;

StoreElem(L, j);

}

ShowElem(L);

int measure;//基准整数

printf("请输入一个整数,以该值为基准把单链表分割为两部分:\n");

scanf_s("%d", &measure);

LNode* p = L;//定义结点,将结点存放的数据与基准数据进行大小比较

for (int i = 0;i < 10; i++)

{

if (p->next->data >= measure)

{

L->Rear->next = p->next;

L->Rear = p->next;

p->next = p->next->next;

L->Rear->next = NULL;

}

else p = p->next;

}

ShowElem(L);

return OK;

}

int main()

{

srand((unsigned int)time(NULL));

LinkList L;

InitList(L);

CreateList(L);

}

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

#include<stdio.h>

#include<stdlib.h>

#include "string.h"

typedef struct StackNode

{

char data;

StackNode* next;

}StackNode, *Stack;

void InitStack(Stack& S)//初始化栈

{

S = NULL;

}

void Push(Stack& S, char data)//前插法压入数据

{

StackNode* tmp = new StackNode;

tmp->data = data;

tmp->next = S;

S = tmp;

}

void Pop(Stack& S)//弹出栈顶数据

{

if (S == NULL) printf("栈空\n");

StackNode* tmp = S;

S = S->next;

delete tmp;

}

char GetTop(Stack& S)//获取栈顶元素

{

if (S == NULL)  return '#';

return S->data;

}

bool match(Stack& S, char data)//配对函数

{

printf("输入元素为: %c\n", data);

if (data == '(' || data == '{' || data == '[') Push(S, data);

else if (data == ')' && GetTop(S) != '(') { printf("配对失败"); return false; }//如果匹配不成功返回错误

else if (data == '}' && GetTop(S) != '{') { printf("配对失败"); return false; }

else if (data == ']' && GetTop(S) != '[') { printf("配对失败"); return false; }

else if (data == ')' && GetTop(S) == '(') { printf("配对成功\n" ); Pop(S); }//匹配成功则弹出栈顶元素,继续匹配

else if (data == '}' && GetTop(S) == '{') { printf("配对成功\n"); Pop(S); }

else if (data == ']' && GetTop(S) == '[') { printf("配对成功\n"); Pop(S); }

return true;

}

bool main()

{

char test[10] = "[{)[]]()#";//测试数据

bool judge = false;

StackNode* S;

InitStack(S);

for (auto c : test)//遍历测试数据,逐一匹配

{

if (c == '#') { printf("测试结束!\n"); break; }//若非要求字符,则退出

judge = match(S, c);//判断是否匹配成功

if (judge == false) break;//如果错误,直接退出

}

if (S != NULL) judge = false;//匹配成功最后栈顶应为空,否则,则有剩余符号,属于匹配失败

if (judge) printf("最终匹配成功\n");

else printf("最终匹配失败\n");

}

  • 实验结果

截屏显示程序的运行结果

         

2.

     

 

3.

4.

(1)

 

(2)

   

五、实验分析

分别截图显示实验过程中出现的问题,分析原因并给出解决方案。

  1. 非递归先序遍历中,调试代码,无法显示出遍历结果

分析:刚开始以为是遍历代码逻辑的问题,但多次修改之后还是无法显示结果。后来发现是有关栈的基本操作出现了逻辑错误,在插入、删除部分,操作对象都是树结点。最后我通过用数组来实现栈的基本操作,调试成功。

非递归先序遍历中,要输出根结点存放的数值及遍历右孩子时引发异常。​​​​​​​

分析:在遍历过程中,列表访问到了尾结点之后还在继续遍历出界,发生越界行为。while循环处加上判断条件p->next即可

void ListDelete_num(LinkList& L, int n, int num)

{

Lnode* p = L; int pla = 1;

while (p->next && num != p->next->data)//若输入整数与p指向的元素的下一个元素不相等,将p指向下一个元素

{

p = p->next;

pla++;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值