SWUST软件技术基础实验笔记

目录

前言

堆栈的操作

实验目的

实验要求

单链表操作

实验目的

实验要求

二叉树操作

实验目的

实验要求

查找与排序

实验目的

实验要求

查找算法

排序算法

实验总结


前言

软件技术基础实验分为四个部分,涵盖了堆栈的操作、单链表操作、二叉树操作以及查找与排序。在课本的附录页面,提供了基础的C语言源码。鉴于本学期选修了C++,我对这些源码进行了一些修改,并补充了扩展的编程要求,且提供了一些思考题。本人因为最常使用的还是Python,所以曾经研究并手写实现过查找与排序算法,当然后面我也补充了C++版本的源码。本篇博客主要面向SWUST的同学们,旨在解释一些关键的部分,帮助大家顺利完成实验并理解其中的要点。

实验环境:Windows 11、Vistual Studio 2022、PyCharm Community Edition 2021.3.1。

堆栈的操作

实验目的

  • 掌握栈的定义;
  • 掌握栈基本操作的实现,并能用于解决实际问题;

实验要求

  • 用顺序存储结构实现栈的基本操作:Push,pop,isempty,isfull,createstack;
  • 利用栈的基本操作实现conversion()函数,该函数能将任意输入的十进制整数转化为二进制形式表示。
  • 扩展要求:修改程序将任意输入的十进制 修改程序将任意输入的十进制整数转化为八进制、十六进制形式表示。
#include<iostream>
#include<cmath>

const int maxsize = 1024;
using namespace std;
typedef int datatype;

//用于规定栈的大小和栈顶
typedef struct {
    datatype elements[maxsize];
    int Top;
}Stack;
//创建空栈
void setStackNull(Stack* S) {
    S->Top = -1;
}
//判满
int isfull(Stack* S) {
    if (S->Top >= maxsize - 1)
        return 1;
    else
        return 0;
}
//判空
int isempty(Stack* S) {
    if (S->Top < 0)
        return 1;
    else
        return 0;
}
//压栈
void push(Stack* S, datatype E) {
    if (isfull(S))
        cout << "Stack Overflow" << endl;
    else {
        S->Top++;
        S->elements[S->Top] = E;
    }
}
//出栈
datatype* pop(Stack* S) {
    datatype* temp;
    if (isempty(S)) {
        cout << "Stack Underflow" << endl;
        return NULL;
    }
    else {
        temp = (datatype*)malloc(sizeof(datatype));
        *temp = S->elements[S->Top];
        S->Top--;
        return (temp);
    }
}
//十进制整数转化为二进制数
void conversion(int n) {
    Stack S;
    setStackNull(&S);
    int r, m;
    r = n;
    while (r) {
        m = r % 2;
        if (isfull(&S))
            cout << "Over flow" << endl;
        else
            push(&S, m);
        r = r / 2;
    }
    cout << "转换后的二进制为:" << endl;
    while (!isempty(&S)) {
        cout << *(pop(&S));
    }
    cout << endl;
}
void conversion2(int n, int r) {
    Stack S;
    int x;
    setStackNull(&S);
    int f = n;
    while (f) {
        if (isfull(&S))
            cout << "Over flow" << endl;
        else
            push(&S, f % r);
        f /= r;
    }
    cout << "数据" << n << "转化为" << r << "进制后的结果为:";
    while (!isempty(&S)) {
        x = *(pop(&S));
        if (x >= 10) {
            cout << (char)('A' + x - 10);
        }
        else {
            cout << x;
        }
    }
    cout << endl;
}
int main() {
    int num;
    cout << "请输入要转换为二进制的十进制数据:" << endl;
    cin >> num;
    conversion(num);

    //扩展3功能
    int n, r;
    cout << "请输入转化的数字以及进制位:" << endl;
    cin >> n >> r;
    conversion2(n, r);

    double mu;
    int nu;
    cout << "请输入m进制转化为n进制中m和n:" << endl;
    cin >> mu >> nu;
    cout << "请输入需要转换的数据:" << endl;
    char arra[1024];
    cin >> arra;
    int s = strlen(arra);
    int sum = 0;
    double j = 0;
    for (int i = s - 1; i >= 0; i--) {
        sum += (arra[i] - '0') * pow(mu, j);
        j++;
    }
    conversion2(sum, nu);
    return 0;
}

d578b162744d42ce899e18f773e10213.png

代码实现了一个栈数据结构,并提供了一些基本的栈操作函数。栈是一种具有后进先出(LIFO)特性的数据结构,通过压栈和出栈操作实现数据的存储和检索。

具体的代码功能如下:

  • 定义了一个结构体 Stack,包含一个数组 elements 用于存储栈的元素,以及一个整数 Top 用于表示栈顶的位置。
  • setStackNull 函数用于将栈置空,即将栈顶 Top 设置为 -1。
  • isfull 函数用于判断栈是否已满,如果栈顶位置 Top 大于等于 maxsize-1,则表示栈已满。
  • isempty 函数用于判断栈是否为空,如果栈顶位置 Top 小于 0,则表示栈为空。
  • push 函数用于将元素压入栈中,如果栈已满,则输出 "Stack Overflow"。
  • pop 函数用于将栈顶元素弹出,并返回其值。如果栈为空,则输出 "Stack Underflow",并返回 NULL。
  • conversion 函数用于将十进制整数转换为二进制数。通过除以 2 的余数来逐步转换,并将余数依次压入栈中。然后从栈中依次弹出并输出二进制数。
  • conversion2 函数用于将一个十进制整数转换为指定进制的数。类似于 conversion 函数,但这里除以的不是 2,而是通过参数 r 指定的进制。
  • 主函数 main 提供了用户交互的界面,可以输入一个十进制数进行转换,以及扩展功能3的操作。

单链表操作

实验目的

  • 掌握线性表的链式存储结构:(1)线性表的链式存储原理;(2)链式存储结构的优缺点;(3)掌握线性表在链式存储结构上的运算
  • 掌握结构体的应用以及数据结点的生成:(1)结构体的定义;(2)动态存储分配函数的使用;(3)强制类型转换的方法
  • 掌握指针的应用:(1)巩固指针的含义和用法;(2)结构体指针的使用

实验要求

  • 完成链表带头结点尾插入法函数。
  • 完成按序号查找函数。
  • 完成插入函数。
  • 扩展要求:完成删除函数。
#include <iostream>
using namespace std;
typedef char datatype;

struct Node {
    datatype data;
    Node* next;
};
typedef Node* linklist;

linklist createlist() {
    char ch;
    linklist head, s, r;
    head = new Node();
    r = head;
    cout << "请输入字符生成链表,以‘#’结束" << endl;
    cin.get(ch);
    while (ch != '#') {
        s = new Node();
        s->data = ch;
        r->next = s;
        r = s;
        cin.get(ch);
    }
    r->next = NULL;  //链表的结束
    return head;   //头指针
}

linklist get(linklist head, int i) {
    int j;        
    linklist p;      
    p = head;
    j = 0;
    while (p->next != NULL && j < i) {  
        p = p->next;
        j++;
    }
    if (i == j)
        return p;
    else
        return NULL;
}

linklist deletelink(linklist head, int i) {
    linklist p = head, q;
    int j = 0;

    while (p ->next != NULL) {  
        j++;
        if (j == i) {
            q = p->next;
            p->next = q->next;
            delete q;
            return head;
        }
        else {
            p = p->next;
        }
    }
    cout << "error" << endl;
    return head;
}

void insertById(linklist head, int i, char x) {
    linklist s, p;
    int j;
    s = new Node();
    s->data = x;
    p = head;
    j = 0;
    while (p != NULL && j < i) {
        j++;
        p = p->next;
    }
    if (p != NULL) {
        s->next = p->next;
        p->next = s;
    }
    else {
        cout << "结点未找到!" << endl;
    }
}

int main() {
    linklist head, r;
    int num;

    head = createlist();
    cout << "链表信息为:";
    r = head->next;
    while (r) {
        cout << r->data;
        r = r->next;
    }
    cout << endl;

    cout << "请输入要查询的序号:" << endl;
    cin >> num;
    r = get(head, num);
    if (r == NULL)
        cout << "没有查到" << endl;
    else
        cout << "查找的结果为:" << r->data << endl;

    cout << "请输入要删除的序号:" << endl;
    int i;
    cin >> i;
    head = deletelink(head, i);
    cout << "删除后链表信息为:";
    r = head->next;
    while (r) {
        cout << r->data;
        r = r->next;
    }
    cout << endl;

    cout << "请输入要插入的序号和字符:" << endl;
    int N;
    char x;
    cin >> N >> x;
    insertById(head, N, x);
    cout << "插入后链表信息为:";
    r = head->next;
    while (r) {
        cout << r->data;
        r = r->next;
    }

    return 0;
}

7653fc700684420c958f9784a61ec2ec.png

这段代码实现了链表的创建、查找、删除和插入等基本操作。

具体的代码功能如下:

  • 定义了一个结构体 Node,包含一个数据成员 data 和一个指向下一个节点的指针 next。
  • 定义了一个类型别名 linklist,表示指向链表节点的指针。
  • createlist 函数用于创建一个链表,用户输入字符并生成链表,以 '#' 结束输入。
  • get 函数用于根据序号获取链表中对应节点的指针,遍历链表直到找到对应位置的节点,返回该节点的指针。
  • deletelink 函数用于删除链表中指定位置的节点,遍历链表直到找到对应位置的节点,删除该节点并释放内存。
  • insertById 函数用于在链表的指定位置插入一个节点,遍历链表直到找到对应位置的节点,插入新节点并更新指针。
  • 在主函数 main 中,通过调用上述函数来执行链表的创建、查找、删除和插入操作,并在控制台输出相应的结果。

二叉树操作

实验目的

  • 掌握二叉树的二叉链表存储结构。掌握二叉树的二叉链表存储结构。
  • 掌握利用二叉树创建方法。
  • 掌握二叉树的先序、中序、后序的递归实现方法。

实验要求

  • 编写创建如图1-1所示二叉树的函数,函数名:create。
  • 编写递归实现二叉树的中序、先序和后序遍历算法。函数名分别为inorder,preorder,postorder。
  • 编写主函数测试以上二叉树的创建和遍历函数。
0d3ab27d78444b50b436b98059c005c4.png

图1-1

#include <iostream>
#include <cstdlib>
using namespace std;

const int maxsize = 1024;
typedef char datatype;
typedef struct node {
    datatype data;
    struct node* lchild;
    struct node* rchild;
} Bitree;

Bitree* CreateTree() {
    char ch;                       //接收用户输入的节点值
    Bitree* Q[maxsize];            //指针数组 Q,用于辅助构建二叉树,指针类型的数组构成队列
    int front, rear;               //用于指示数组 Q 的前后位置
    Bitree* root, * s;             //指针变量 root 和 s
    root = NULL;                   //初始时二叉树为空
    front = 1;                     //表示数组 Q 的初始状态
    rear = 0;

    cout << "请输入二叉树的各个结点,@表示虚结点,#表示结束:" << endl;
    cin >> ch;
    while (ch != '#') {
        cout << ch;
        s = NULL;            //s 初始化为 NULL
        if (ch != '@') {                                                      
            s = (Bitree*)malloc(sizeof(Bitree));                   
            s->data = ch;                       //节点值赋值给 s 的 data 成员
            s->lchild = NULL;//s 的左孩子指针 lchild 
            s->rchild = NULL; //s 的右孩子指针 lchild 
        }
        rear++;                                 //rear 增加 1,并将 s 存储在 Q 数组的对应位置
        Q[rear] = s;
        if (rear == 1)                          //rear 的值为 1,即为第一个节点,将 root 指向 s
            root = s;
        else {
            if (s && Q[front])
                if (rear % 2 == 0)
                    Q[front]->lchild = s;       //如果是偶数,则将s赋值给Q[front]节点的左孩子指针lchild
                else
                    Q[front]->rchild = s;
            if (rear % 2 == 1)                  //前节点是一个新的层级的节点
                front++;
        }                                       //指向下一层的节点,指针 front 向下移动
        cin >> ch;
    }
    return root;                                //返回二叉树的根节点指针root。
}

void preorder(Bitree* p) {
    if (p != NULL) {
        cout << " " << p->data << " ";
        preorder(p->lchild);                    //以当前节点 p 的左孩子作为参数,实现前序遍历左子树。
        preorder(p->rchild);
    }
}

void inorder(Bitree* p) {
    if (p != NULL) {
        inorder(p->lchild);                     //当前节点 p 的左孩子作为参数,实现中序遍历左子树
        cout << " " << p->data << " ";
        inorder(p->rchild);
    }
}

void postorder(Bitree* p) {
    if (p != NULL) {
        postorder(p->lchild);
        postorder(p->rchild);
        cout << " " << p->data << " ";
    }
}

int main() {
    Bitree* root;
    root = CreateTree();
    cout << "\n先序遍历结果如下:" << endl;
    preorder(root);
    cout << "\n中序遍历结果如下:" << endl;
    inorder(root);
    cout << "\n后序遍历结果如下:" << endl;
    postorder(root);
    cout << endl;
    return 0;
}

10ce3d4bdc85471cb75fadc847728a3b.png

这段代码实现了二叉树的基本操作。

具体的代码功能如下:

  • ch接收用户输入的节点值、指针数组 Q,用于辅助构建二叉树,指针类型的数组构成队列、front表示队列Q的前部位置,用于指示下一个节点应该插入到哪个位置、rear表示队列Q的尾部位置,用于指示当前队列中最后一个节点的位置
  • rear为奇数时,表示当前节点是一个新的层级的节点,需要递增front,以便在下一次插入节点时,将新节点链接到正确的父节点。front指示下一个节点的插入位置,rear表示当前队列中最后一个节点的位置
  • preorder、inorder、postorder为先序遍历、中序遍历、后续遍历
  • 主函数main 中,通过调用上述函数来执行链表的创建、查找、删除和插入操作,并在控制台输出相应的结果

查找与排序

实验目的

  • 了解数据查找的一系列方法:(1)了解查找表的分类;(2)掌握折半查找法的原理
  • 掌握各种排序(简单插入,简单选择,冒泡排序,快速排序等)方法及适用场合,并能在解决实际问题时灵活应用。
  • 了解查找与排序在实际生活中的应用。

实验要求

  • 顺序查找:首先从键盘输入一个数据序列生成一个顺序表,然后从键盘上任意输入一个值,在顺序表中进行查找。
  • 折半查找:任意输入一组数据作为各数据元素的键值,首先将此序列进行排序,然后在该有序表上使用折半查找算法进行对给定值的查找。
  • 对于给定的某无序序列,分别用直接插入、希尔排序、快速排序等方法进行排序,并输出每种排序下的各趟排序结果。

查找算法

基本要求是做这两个,重点还是理解折半查找。

a.顺序查找


#include <iostream>
#include <vector>
using namespace std;

typedef int datatype;
typedef struct
{
    vector<datatype> elem;
    int length;
} Stable;

void create(Stable* l)
{
    cout << "请输入顺序表的内容:" << endl;
    for (int i = 0; i < l->length; i++)
    {
        datatype data;
        cout << "l.elem[" << i + 1 << "] = ";
        cin >> data;
        l->elem.push_back(data);
    }
}

void s_search(const Stable* l, datatype k)
{
    bool found = false;
    for (int i = 0; i < l->length; i++)
    {
        if (l->elem[i] == k)
        {
            cout << "查找成功." << endl;
            found = true;
            cout << "l.elem[" << i + 1 << "] = " << k << endl;
        }
    }
    if (!found)
    {
        cout << "没有找到数据" << k << "!" << endl;
    }
}

int main()
{
    Stable table;
    datatype key;

    cout << "请输入顺序表的长度: ";
    cin >> table.length;

    create(&table);

    cout << "创建的顺序表内容:" << endl;
    for (int i = 0; i < table.length; i++)
    {
        cout << "l.elem[" << i + 1 << "] = " << table.elem[i] << endl;
    }

    cout << "输入查找关键字: ";
    cin >> key;

    s_search(&table, key);

    return 0;
}

示例: 

c395af01bcea465da9e0050641c73ff4.png

b.折半查找

#include <iostream>
using namespace std;

const int MAX = 100;

typedef struct {
    int element[MAX + 1];
    int length;
} Stable;

void create_seq(Stable* l)
{
    cout << "请输入顺序表的内容:" << endl;
    for (int i = 0; i < l->length; i++)
    {
        cout << "l.element[" << i + 1 << "] = ";
        cin >> l->element[i];
    }
}

void sort_seq(Stable* l)
{
    int flag, t;
    for (int i = 0; i < l->length - 1; i++)
    {
        flag = 0;
        for (int j = 0; j < (l->length) - 1 - i; j++)
        {
            if (l->element[j] > l->element[j + 1])
            {
                t = l->element[j + 1];
                l->element[j + 1] = l->element[j];
                l->element[j] = t;
                flag = 1;
            }
        }
        if (flag == 0)
            break;
    }
}

int sea_self(const Stable* l, int k, int low, int high)
{
    if (low > high)
    {
        cout << "没有找到查找的值" << endl;
        return -1;
    }
    int mid = (low + high) / 2;
    if (l->element[mid] == k)
    {
        cout << "查找成功" << endl;
        cout << "l[" << mid + 1 << "] = " << k << endl;
        return mid;
    }
    else
    {
        if (l->element[mid] < k)
            return sea_self(l, k, mid + 1, high);
        else
            return sea_self(l, k, low, mid - 1);
    }
}

int main()
{
    Stable table;
    int key;

    cout << "请输入线性表的长度:";
    cin >> table.length;

    create_seq(&table);

    sort_seq(&table);

    cout << "排序后的数据" << endl;
    for (int i = 0; i < table.length; i++)
    {
        cout << "l[" << i + 1 << "] = " << table.element[i] << endl;
    }

    cout << "请输入查找的值:" << endl;
    cin >> key;

    sea_self(&table, key, 0, table.length - 1);

    return 0;
}

示例: 

8e6ae178cafb4163bf754cba405ae66f.png

排序算法

实现插入排序、希尔排序、快速排序。

a.Python

# 插入排序
def insert_sort(R):
    for i in range(1, len(R)):
        temp = R[i]
        j = i - 1
        while j >= 0 and temp['key'] < R[j]['key']:
            R[j + 1] = R[j]
            j -= 1
        R[j + 1] = temp

# 希尔排序
def shell_sort(R):
    n = len(R)
    h = n // 2
    while h > 0:
        for j in range(h, n):
            temp = R[j]
            i = j - h
            while i >= 0 and temp['key'] < R[i]['key']:
                R[i + h] = R[i]
                i -= h
            R[i + h] = temp
        h //= 2

# 快速排序
def partition(R, low, high):                                  #用于划分数组并返回基准元素的位置。它通过交换元素的方式将小于基准的元素放在基准的左边,大于基准的元素放在基准的右边。
    i = low
    j = high
    pivot = R[i]
    while i < j:
        while i < j and R[j]['key'] >= pivot['key']:
            j -= 1
        if i < j:
            R[i] = R[j]
            i += 1
        while i < j and R[i]['key'] < pivot['key']:
            i += 1
        if i < j:
            R[j] = R[i]
            j -= 1
    R[i] = pivot
    return i

def quick_sort(R, low, high):
    if low < high:
        pivot_pos = partition(R, low, high)
        quick_sort(R, low, pivot_pos - 1)
        quick_sort(R, pivot_pos + 1, high)

if __name__ == "__main__":
    # 26 5 37 1 61 11 59 15 48 19
    s = 11
    R = [{'key': 0} for _ in range(s)]

    # 插入排序
    print("请输入使用插入算法排序的10个数据,以空格分隔:")
    input_str = input()
    input_list = input_str.split()
    for i in range(1, s):
        R[i]['key'] = int(input_list[i-1])
    print("插入排序之前:")
    for i in range(1, s):
        print(R[i]['key'], end="\t")
    insert_sort(R)
    print("\n插入排序之后:")
    for i in range(1, s):
        print(R[i]['key'], end="\t")

    # 希尔排序
    print("\n请输入使用希尔算法排序的10个数据,以空格分隔:")
    input_str = input()
    input_list = input_str.split()
    for i in range(s-1):
        R[i]['key'] = int(input_list[i])
    print("\n希尔排序之前:")
    for i in range(s-1):
        print(R[i]['key'], end="\t")
    shell_sort(R)
    print("\n希尔排序之后:")
    for i in range(s-1):
        print(R[i]['key'], end="\t")

    # 快速排序
    print("\n请输入使用快排算法排序的10个数据,以空格分隔:")
    input_str = input()
    input_list = input_str.split()
    for i in range(1, s):
        R[i]['key'] = int(input_list[i-1])
    print("\n快排排序之前:")
    for i in range(1, s):
        print(R[i]['key'], end="\t")
    quick_sort(R, 1, s-1)
    print("\n快排排序之后:")
    for i in range(1, s):
        print(R[i]['key'], end="\t")

示例:

82484ffa37e84ea2bc47f46ea8e73a63.png

b.C++

#include<iostream>
#include<ctime>
#include<cstdio>
#include<cstring>
using namespace std;
const int s = 11;
typedef char datatype;
typedef struct
{
    int key;
    datatype others;//记录的其他域
} rectype;
/*插入排序*/
void InsertSort(rectype R[])
{
    int i, j;
    for (i = 2; i < s; i++)//插入的数据分别在1到n当中
    {
        memcpy(&R[0], &R[i], sizeof(rectype));
        j = i - 1;
        while (R[0].key < R[j].key)
        {
            R[j + 1] = R[j];//将关键字大于R[i].key 记录后移
            j--;
        }
        R[j + 1] = R[0];
    }
}
/*希尔排序*/
void ShellSort(rectype R[], int n)
{
    int i, j, h;
    rectype temp;
    h = n / 2;
    while (h > 0)
    {
        for (j = h; j <= n - 1; j++)
        {
            temp = R[j];
            i = j - h;
            while ((i >= 0) && temp.key < R[i].key)
            {
                R[i + h] = R[i];
                i = i - h;
            }
            R[i + h] = temp;

        }
        h /= 2;//增量为1排序后终止算法
    }

}
int Partition(rectype R[], int l, int h)
{
    int i, j;
    rectype temp;
    i = l;
    j = h;
    temp = R[i];//快排第一次的基准
    int flag = 1;//修改flag
    while (flag)
    {
        while ((R[j].key >= temp.key) && (i < j))
            j--;
        if (i < j)
            R[i++] = R[j];
        while ((R[i].key < temp.key) && (i < j))
            i++;
        if (i < j)
            R[j--] = R[i];
        if (i == j)
            flag = 0;
    }//这段可以结合快排算法结合理解
    R[i] = temp;
    return i;
}
void QuickSort(rectype R[], int s1, int t1)
{
    int i;
    if (s1 < t1)
    {
        i = Partition(R, s1, t1);//对R[s1]~R[t1]作划分
        QuickSort(R, s1, i - 1);
        QuickSort(R, i + 1, t1);
    }
}
int main()
{
    // /t的含义是跳格
    rectype R[s];
    int i;
    /*插入测试*/
    cout << "请输入使用插入算法排序的10个数据" << endl;
    for (i = 1; i < s; i++)
    {
        cin >> R[i].key;
    }
    cout << "插入排序之前" << endl;
    for (i = 1; i < s; i++)
    {
        cout << R[i].key << "\t";
    }
    InsertSort(R);
    cout << endl << "插入排序之后" << endl;
    for (i = 1; i < s; i++)
    {
        cout << R[i].key << "\t";
    }
    /*希尔测试*/
    cout << endl << "请输入使用希尔算法排序的10个数据" << endl;
    for (i = 0; i < s - 1; i++)
    {
        cin >> R[i].key;
    }
    cout << endl << "希尔排序之前" << endl;
    for (i = 0; i < s - 1; i++)
    {
        cout << R[i].key << "\t";
    }
    ShellSort(R, 10);
    cout << endl << "希尔排序之后" << endl;
    for (i = 0; i < s - 1; i++)
    {
        cout << R[i].key << "\t";
    }
    /*快排测试*/
    cout << endl << "请输入使用快排算法排序的10个数据" << endl;
    for (i = 1; i < s; i++)
    {
        cin >> R[i].key;
    }
    cout << endl << "快排排序之前" << endl;
    for (i = 1; i < s; i++)
    {
        cout << R[i].key << "\t";
    }
    QuickSort(R, 1, 10);
    cout << endl << "快排排序之后" << endl;
    for (i = 1; i < s; i++)
    {
        cout << R[i].key << "\t";
    }
}

示例: 

6f071f83813d4d7a941b14871a8ddcfc.png

实验总结

祝各位同学能够顺利的完成实验,师兄先给未来的大佬们敬杯茶。

猜你喜欢

转载自blog.csdn.net/m0_62919535/article/details/130799196
今日推荐