【编译原理】编程语言认知

实验2:编程语言认知

一:实验目的

1:强化对编译器两端的认识。

2:了解语言多样性。

3:了解语言特性对语言实现的影响。

二:实验环境

自选多个不同的语言环境。

编号

所用语言

程序编写的软件环境

1

C

Dev-C++

2

C++

Dev-C++

3

Python

Visual Studio Code

4

Java

IntelliJ IDEA Community

5

R

RStudio

6

JavaScript

Visual Studio Code

7

Matlab

MATLAB R2022a

三:实验要求

    使用三种以上(如C、C++、C#、Python、Java)的不同语言实现:对数组中的数据快速排序,并对语言易用性、程序性能进行比较分析,撰写实验报告。

四:算法思想

    快速排序的基本思想是:通过一趟排序将待排数组分割成独立的两部分,其中一部分数组的关键字均比另一部分数组的关键字小,则可分别对这两部分数组进行排序,以达到整个数组排序的目的。

五:实验过程

(1)写出快速排序程序流程图。

(2)选择三种以上语言环境。

(3)编写快速排序程序。

(4)结果验证截图。

(5)撰写实验报告。

六:实验内容

1:快排的程序流程图

快排算法的主要思想是:先从数组中取出一个基准数(一般情况下取左边第一个数),通过一趟排序将要排序的数组划分为独立的两个部分,要求是一趟排序完成后,基准数的左边的数都小于基准数,基准数的右边的数都大于基准数。然后按照此方法对这两部分数组分别进行快速排序,整个排序过程用递归进行,直至整个数组变成有序数组。

根据算法思想,可以画出快排的程序流程图。

主函数(main、quicksort)部分如下图所示。

分块函数(part)部分如下图所示。

2:各类编程语言的快排代码与结果

【0】测试用例设计

在本次实验中,测试用例采用1到10000降序排列的整数。即数组的第一项为10000,相邻的前后两个项的间隔为1,数组的最后一项为1。

为了防止程序的偶然性,本次实验将在每种语言编写的程序下运行5次,并计算5次运行所消耗的时间,取其平均值作为该编程语言在快速排序算法上的程序性能指标

【1】C语言

(1)程序快排代码

    本次实验在C语言上编写的快排代码如下表所示。

#include <stdio.h>

#include <malloc.h>

#include <time.h>

// segment-each-part function

int part(int *arr, int low, int high){

    int t=arr[high],i=low-1,j;

   

    for(j=low;j<high;j++){

        if(arr[j]<=t){

            i++;

            int temp=arr[i];

            arr[i]=arr[j];

            arr[j]=temp;

        }

    }

   

    int swap=arr[i+1];

    arr[i+1]=arr[high];

    arr[high]=swap;

    return i+1;

}

// quick-sort function

void QuickSort(int *arr, int low, int high){

    if(low<high){

        int mid=part(arr,low,high);

        QuickSort(arr,low,mid-1);

        QuickSort(arr,mid+1,high);

    }

}

int main(){

    // input part

    int n=10000;

    // printf("please input total number: ");

    // scanf("%d",&n);

    int *arr=(int*)malloc(sizeof(int)*n);

    int i=0;

    // printf("please input each figure: ");

    for(i=0;i<n;i++){

        // scanf("%d",&arr[i]);

        arr[i]=10000-i;

    }

   

    /*

    printf("the test example of array is as follows: \n");

    for(i=0;i<n;i++){

        // scanf("%d",&arr[i]);

        printf("%d ",arr[i]);

    }

    printf("\n");

    */

   

    // quick sort & timing

    clock_t start=clock();

    QuickSort(arr,0,n-1);

    clock_t end=clock();

   

    // output part

    printf("the result after quick sort is as follows: \n");

    for(i=0;i<n;i++){

        printf("%d ",arr[i]);

    }

    printf("\n\n\n");

   

    double period=((double)(end-start))/CLOCKS_PER_SEC;

    printf("the calculation time is: %f \n", period);

    return 0;

}

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【2】C++

(1)程序快排代码

本次实验在C++上编写的快排代码如下表所示。

#include <iostream>

#include <vector>

#include <ctime>

using namespace std;

// segment-each-part function

int part(vector<int>& arr, int low, int high) {

    int t=arr[high],i=low-1,j;

    for(j=low;j<high;j++){

        if (arr[j]<=t){

            i++;

            int temp=arr[i];

            arr[i]=arr[j];

            arr[j]=temp;

        }

    }

    int swap=arr[i + 1];

    arr[i+1]=arr[high];

    arr[high]=swap;

    return i+1;

}

// quick-sort function

void QuickSort(vector<int>& arr, int low, int high){

    if(low<high) {

        int mid=part(arr,low,high);

        QuickSort(arr,low,mid-1);

        QuickSort(arr,mid+1,high);

    }

}

int main(){

    int n=10000;

    vector<int> arr(n);

    for(int i=0;i<n;i++){

        arr[i]=10000-i;

    }

    // quick sort & timing

    clock_t start=clock();

    QuickSort(arr,0,n-1);

    clock_t end=clock();

    // output part

    cout << "the result after quick sort is as follows: \n";

    for(int i=0;i<n;i++){

        cout<<arr[i]<<" ";

    }

    cout<<endl<<endl<<endl;

    double period=((double)(end-start))/CLOCKS_PER_SEC;

    cout<<"the calculation time is: "<<period;

    return 0;

}

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【3】Python

(1)程序快排代码

本次实验在Python上编写的快排代码如下表所示。

import time

# segment-each-part function

def part(arr, low, high):

    t = arr[high]

    i = low - 1

    for j in range(low, high):

        if arr[j] <= t:

            i += 1

            arr[i], arr[j] = arr[j], arr[i]

    arr[i + 1], arr[high] = arr[high], arr[i + 1]

    return i + 1

# quick-sort function

def quick_sort(arr, low, high):

    stack = [(low, high)]

    while stack:

        low, high = stack.pop()

        if low < high:

            mid = part(arr, low, high)

            stack.append((low, mid - 1))

            stack.append((mid + 1, high))

if __name__ == "__main__":

    n = 10000

    arr = [10000 - i for i in range(n)]

    # quick sort & timing

    start_time = time.time()

    quick_sort(arr, 0, n - 1)

    end_time = time.time()

    # output part

    print("the result after quick sort is as follows: ")

    print(*arr)

    period = end_time - start_time

    print("the calculation time is:", period, "seconds")

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【4】Java

(1)程序快排代码

本次实验在Java上编写的快排代码如下表所示。

import java.util.Arrays;

public class QuickSort {
   
// segment-each-part function
   
static int part(int[] arr, int low, int high) {
       
int t = arr[high];
       
int i = low - 1;

       
for (int j = low; j < high; j++) {
           
if (arr[j] <= t) {
                i++;
               
int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

       
int swap = arr[i + 1];
        arr[i +
1] = arr[high];
        arr[high] = swap;
       
return i + 1;
    }

   
// quick-sort function
   
static void quickSort(int[] arr, int low, int high) {
       
if (low < high) {
           
int mid = part(arr, low, high);
            quickSort(arr, low, mid -
1);
            quickSort(arr, mid +
1, high);
        }
    }

   
public static void main(String[] args) {
       
int n = 10000;
       
int[] arr = new int[n];
       
for (int i = 0; i < n; i++) {
            arr[i] =
10000 - i;
        }

       
// quick sort & timing
       
long startTime = System.nanoTime();
        quickSort(arr,
0, n - 1);
       
long endTime = System.nanoTime();

       
// output part
       
System.out.println("the result after quick sort is as follows: ");
        System.out.println(Arrays.toString(arr));

       
double period = (endTime - startTime) / 1e9; // convert nanoseconds to seconds
       
System.out.println("the calculation time is: " + period);
    }
}

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【5】R

(1)程序快排代码

本次实验在R上编写的快排代码如下表所示。

partition <- function(arr, low, high) {

  pivot <- arr[high]

  i <- low - 1

 

  for (j in low:(high-1)) {

    if (arr[j] <= pivot) {

      i <- i + 1

      temp <- arr[i]

      arr[i] <- arr[j]

      arr[j] <- temp

    }

  }

 

  temp <- arr[i + 1]

  arr[i + 1] <- arr[high]

  arr[high] <- temp

 

  return(list('i' = i + 1, 'arr' = arr))

}

quick_sort <- function(arr, low, high) {

  stack <- list(c(low, high))

 

  while (length(stack) > 0) {

    indices <- stack[[length(stack)]]

    stack <- stack[-length(stack)]

    low <- indices[1]

    high <- indices[2]

   

    if (low < high) {

      res <- partition(arr, low, high)

      mid <- res$i

      arr <- res$arr

      stack <- c(stack, list(c(low, mid - 1)), list(c(mid + 1, high)))

    }

  }

 

  return(arr)

}

# Main block

n <- 10000

arr <- n:1

# Timing the quick sort

start_time <- Sys.time()

arr <- quick_sort(arr, 1, n)  # Ensure arr is reassigned with the sorted array

end_time <- Sys.time()

# Output

cat("The result after quick sort is as follows (first 10 elements shown for brevity):\n")

print(arr)

period <- end_time - start_time

cat("The calculation time is:", period)

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【6】JavaScript

(1)程序快排代码

本次实验在JavaScript上编写的快排代码如下表所示。

<!DOCTYPE html>

<html>

<head>

    <title>Quick Sort JavaScript</title>

</head>

<body>

    <script>

        function partition(arr, low, high) {

            let pivot = arr[high];

            let i = low - 1;

            for (let j = low; j < high; j++) {

                if (arr[j] <= pivot) {

                    i++;

                    [arr[i], arr[j]] = [arr[j], arr[i]]; // Swapping using destructuring

                }

            }

            [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; // Swap pivot into the correct place

            return i + 1;

        }

        function quickSort(arr, low, high) {

            let stack = [[low, high]];

            while (stack.length > 0) {

                const [start, end] = stack.pop();

                if (start < end) {

                    const mid = partition(arr, start, end);

                    stack.push([start, mid - 1]);

                    stack.push([mid + 1, end]);

                }

            }

        }

        function main() {

            const n = 10000;

            const arr = Array.from({ length: n }, (_, index) => 10000 - index);

            const startTime = new Date().getTime(); // Start timing

            quickSort(arr, 0, n - 1);

            const endTime = new Date().getTime(); // End timing

            // Output part

            console.log("The result after quick sort is as follows: ");

            console.log(arr.join(" ")); // Joining array elements for cleaner output

            const period = (endTime - startTime) / 1000; // Convert milliseconds to seconds

            console.log("The calculation time is:", period, "seconds");

        }

        main();

    </script>

</body>

</html>

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

【7】Matlab

(1)程序快排代码

本次实验在Matlab上编写的快排代码如下表所示。

function QuickSortDemo

    % 主函数入口

    n = 10000;

    arr = 10000:-1:1; % 生成一个从10000递减到1的数组

    tic; % 开始计时

    arr = QuickSort(arr, 1, n); % 快速排序

    toc; % 结束计时并输出所用时间

    % 输出排序后的数组

    fprintf('The result after quick sort is as follows:\n');

    disp(arr(1:100)); % 仅展示前100个元素以节省空间

end

function arr = QuickSort(arr, low, high)

    % 快速排序函数

    if low < high

        [arr, mid] = Partition(arr, low, high); % 分区操作

        arr = QuickSort(arr, low, mid-1); % 递归排序左半部分

        arr = QuickSort(arr, mid+1, high); % 递归排序右半部分

    end

end

function [arr, mid] = Partition(arr, low, high)

    % 分区函数

    pivot = arr(high);

    i = low - 1;

    for j = low:high-1

        if arr(j) <= pivot

            i = i + 1;

            temp = arr(i);

            arr(i) = arr(j);

            arr(j) = temp; % 交换元素

        end

    end

    % 把基准值换到中间

    temp = arr(i+1);

    arr(i+1) = arr(high);

    arr(high) = temp;

    mid = i + 1;

end

(2)程序测试结果

测试用例在执行文件下的5次运行结果如下图所示。

3:编程语言对比分析

(1)语言易用性

编程语言的易用性可以根据以下几个维度来进行评估:语法简洁性、内置函数库的支持、内存管理、类型系统、开发和调试工具的可用性。

在本次实验快速排序算法的实现中,各类编程语言的可用性对比,如下表所示。

编程语言

易用性等级

原因

C

较低

C语言需要手动管理数组的内存,且语法较为繁琐。实现快排时,指针操作和手动交换元素增加了实现难度。

C++

中等

C++在C的基础上增加了类、模板、STL等面向对象和泛型编程的特性,使得编写快排更灵活。

Python

较高

Python的简洁语法、动态类型系统和丰富的标准库保证了实现过程非常简单快捷。

Java

中等

Java提供了强类型系统和丰富的标准库,但语法更繁琐。实现快排需要明确处理数组索引和递归逻辑。

R

较低

R语言更多地依赖于循环和条件判断,与R擅长的数据操作范式略有不同。

JavaScript

中等

JavaScript的动态类型和灵活的数组操作使得实现快排较为简单,但递归深度有一定限制。

Matlab

较高

Matlab对递归有很好的支持,用户不需要担心递归导致的栈溢出问题,同时数组的索引、切片和赋值操作非常简洁明了。

    综上所述,在编程语言的易用性方面,Python和Matlab位于第一梯队,C++、Java和JavaScript位于第二梯队,C和R位于第三梯队。

(2)程序性能

    统计各类编程语言在相同复杂度问题下的快速排序结果,如下表所示。其中,时间的单位均为秒(second)。

编程语言

测试1时间

测试2时间

测试3时间

测试4时间

测试5时间

平均耗时

C

0.121

0.126

0.122

0.123

0.12

0.1224

C++

0.263

0.268

0.269

0.275

0.278

0.2706

Python

3.17

3.346

3.147

3.32

3.2

3.2366

Java

0.0373

0.0368

0.0374

0.0349

0.0384

0.03696

R

4.859

4.984

4.873

4.867

4.921

4.9008

JavaScript

0.078

0.091

0.08

0.078

0.082

0.0818

Matlab

0.241

0.111

0.101

0.115

0.101

0.1338

由上表可知,从平均耗时的角度来看,各个编程语言从快到慢的排序依次为:Java、JavaScript、C、Matlab、C++、Python、R。

由此可知,各个编程语言在执行相同复杂度的快速排序问题时,性能表现存在显著差异。这些差异主要受到语言的运行环境、编译器优化水平、以及语言本身的设计方法等因素的影响。

七:心得与思考

1:在Python中,递归调用次数超过默认的最大递归深度限制,会导致递归错误(RecursionError),显示如下报错。

File "c:\Users\86158\Desktop\import time.py", line 19, in quick_sort

    mid = part(arr, low, high)

          ^^^^^^^^^^^^^^^^^^^^

RecursionError: maximum recursion depth exceeded.

为了解决这个问题,可以使用以下两种方法。(1)增加递归深度限制:通过 sys.setrecursionlimit() 函数来增加递归深度限制,但可能会导致堆栈溢出。(2)改用非递归实现:使用例如堆栈等方法来模拟递归的调用过程,避免递归深度限制的问题,使程序更加灵活和可控。

2:在Java中,公共类的类名必须与文件名完全相同(包括大小写)。否则会出现如下报错。

User

PS C:\Users\86158\IdeaProjects\untitled1> javac sort.java

sort.java:3: 错误: 类 QuickSort 是公共的, 应在名为 QuickSort.java 的文件中声明

public class QuickSort {

       ^

1 个错误

3:Java文件的运行需要先安装JDK(Java开发工具包),然后通过javac指令编译Java文件,最后通过java指令运行Java程序。

4:在Dev环境下中的C语言,使用for循环的时候不能和C++一样,将迭代变量第一次定义在循环内部,而需要写在循环外面。示例如下。

C语言写法

int i;

for(i=0;i<100;i++)

C++写法

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

5:不是所有编程语言都能在大量数据的情况下实现递归。在本次实验中,C语言、C++、Java、Matlab可以实现快排的递归写法,而Python、R、JavaScript需要通过非递归的写法实现,否则堆栈会出现溢出的情况(爆栈)。

6:各类编程语言的执行性能原因分析,如下表所示。

编程语言

程序性能

原因

C

中等

C语言的编译器能够生成高度优化的机器码,属于接近硬件层面的编程语言。

C++

中等

C++相比C而言,在提供更多抽象和特性的同时,也可能引入了一些性能开销。

Python

较低

Python是一种解释型语言,其运行时性能相比编译型语言通常较低。

Java

较高

Java虚拟机(JVM)的高度优化,包括即时编译器(JIT)的使用,可以在运行时将Java字节码转换为接近本地代码的性能。

R

较低

R语言主要用于统计分析和图形表示,其在数据处理方面非常强大,但在执行计算密集型算法时可能不如专为性能优化设计的语言。

JavaScript

较高

JavaScript引擎(如V8)的显著优化,以及现代浏览器对JavaScript执行的优化,极大提高了其性能。

Matlab

中等

MATLAB专为数值计算和科学计算设计,其解释执行的特性可能在某些情况下影响性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MorleyOlsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值