数据结构实训——排序

实训七   排序算法实现(一)

一、实训类型

   验证性实训

二、实训目的与任务

1.掌握直接插入排序算法的基本思想及实现方法;

2. 掌握希尔插入排序算法的基本思想及实现方法;

3. 掌握冒泡排序算法的基本思想及实现方法;

4. 掌握快速排序算法的基本思想及实现方法;

5. 分析各种排序算法的时间复杂度。

三、实训基本原理

1. 直接插入排序

基本思想是:

依次将待排序序列中的每一个记录插入到一个已排好序的序列中,直到全部记录都排好序。

具体的排序过程:

⑴ 将整个待排序的记录序列划分成有序区和无序区,初始时有序区为待排序记录序列中的第一个记录,无序区包括所有剩余待排序的记录;

⑵ 将无序区的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录;

⑶ 重复执行⑵,直到无序区中没有记录为止。

2. 起泡排序

基本思想是:

两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。

具体的排序过程:

⑴ 将整个待排序的记录序列划分成有序区和无序区,初始状态有序区为空,无序区包括所有待排序的记录。

⑵ 对无序区从前向后依次将相邻记录的关键码进行比较,若反序则交换,从而使得关键码小的记录向前移,关键码大的记录向后移(像水中的汽泡,体积大的先浮上来)。

⑶ 重复执行⑵,直到无序区中没有反序的记录。

3. 双向起泡排序

基本思想是:从两端(奇数趟排序从前向后,偶数趟排序从后向前)两两比较相邻记录,如果反序则交换,直到没有反序的记录为止。

4. 快速排序

快速排序(Quick Sort)是对起泡排序的一种改进,改进的着眼点是:增大记录的比较和移动距离,使关键码较大的记录一次就能从前面移动到后面,关键码较小的记录一次就能从后面移动到前面,记录移动的距离较远,从而减少了总的比较次数和移动次数。

基本思想是:首先选一个轴值(即比较的基准),将待排序记录分割成独立的两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码均大于或等于轴值,然后分别对这两部分重复上述过程,直到整个序列有序。

四、实训设备

1.计算机

五、实训内容

1. 对一组数据进行直接插入排序(按升序排列)。

2. 对一组数据进行起泡排序(按升序排列)。

3. 对一组数据进行快速排序(按升序排列)。

4. 直接插入排序基于单链表的实现(设计实训选作)。

5. 对一组数据进行双向起泡排序(按升序排列)(设计实训选作)。、

代码:

  1. 对一组数据进行直接插入排序(按升序排列)

#include <stdio.h>

#define MAXSIZE 100

// 定义关键字类型为int

typedef int KeyType;

// 定义线性表元素结构体

typedef struct

{

    KeyType Key;

} LineList;

// 直接插入排序函数

void insertSort(LineList r[], int n)

{

    int i, j;

    for (i = 1; i < n; i++) // 从第二个元素开始,所以i初始化为1,循环条件是i小于n

    {

        r[0] = r[i]; // 将当前要插入的元素暂存到r[0],一般r[0]作为临时存储单元

        j = i - 1;

        while (j >= 0 && r[0].Key < r[j].Key) // 这里修改语法错误,比较当前暂存元素和已排序部分元素的关键字大小

        {

            r[j + 1] = r[j]; // 将比暂存元素大的元素往后移一位

            j--;

        }

        r[j + 1] = r[0]; // 将暂存的元素插入到合适位置

    }

}

int main()

{

    LineList list[MAXSIZE];

    int num, i;

    printf("请输入要排序的数据个数(小于等于 %d ):", MAXSIZE - 1);

    scanf("%d", &num);

    // 输入数据

    printf("请依次输入 %d 个整数:\n", num);

    for (i = 1; i <= num; i++)

    {

        scanf("%d", &list[i].Key);

    }

    // 调用插入排序函数进行排序

    insertSort(list, num + 1);

    // 输出排序后的结果

    printf("排序后的结果为:\n");

    for (i = 1; i <= num; i++)

    {

        printf("%d ", list[i].Key);

    }

    printf("\n");

    return 0;

}

2. 对一组数据进行起泡排序(按升序排列)。

#include <stdio.h>

#define MAXSIZE 100

// 定义关键字类型为int

typedef int KeyType;

// 定义线性表元素结构体

typedef struct

{

    KeyType Key;

} LineList;

// 冒泡排序算法函数

void BubbleSort(LineList r[], int n)

{

    int i, j, exchange;

    LineList temp;

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

    {

        exchange = 0;

        // 本趟比较是否有交换变量,初始化为0表示本趟暂未交换

        for (j = 1; j <= n - i; j++)

            // 从第1个到第n - i个记录进行一趟比较

            if (r[j].Key > r[j + 1].Key)

            {

                // 若前面记录大于后面记录则交换

                temp = r[j];

                r[j] = r[j + 1];

                r[j + 1] = temp;

                exchange = 1;

            }

        if (exchange == 0)

            return;

    }

}

int main()

{

    LineList list[MAXSIZE];

    int num, i;

    printf("请输入要排序的数据个数(小于等于 %d ):", MAXSIZE - 1);

    scanf("%d", &num);

    // 输入数据

    printf("请依次输入 %d 个整数:\n", num);

    for (i = 1; i <= num; i++)

    {

        scanf("%d", &list[i].Key);

    }

    // 调用冒泡排序函数进行排序

    BubbleSort(list, num + 1);

    // 输出排序后的结果

    printf("排序后的结果为:\n");

    for (i = 1; i <= num; i++)

    {

        printf("%d ", list[i].Key);

    }

    printf("\n");

    return 0;

}

3. 对一组数据进行快速排序(按升序排列)。

#include <stdio.h>

#define MAXSIZE 100

// 定义关键字类型为int

typedef int KeyType;

// 定义线性表元素结构体

typedef struct

{

    KeyType Key;

} LineList;

// 快速排序函数

void QuickSort(LineList r[], int first, int end)

{

    int i, j;

    LineList temp;

    if (first < end)

    {

        i = first;

        j = end;

        temp = r[first];  // 选取第一个元素作为基准值

        while (i < j)

        {

            // 从右往左找第一个小于基准值的元素

            while (i < j && r[j].Key >= temp.Key)

                j--;

            r[i] = r[j];

            // 从左往右找第一个大于基准值的元素

            while (i < j && r[i].Key <= temp.Key)

                i++;

            r[j] = r[i];

        }

        r[i] = temp;  // 将基准值放到合适的位置

        // 对基准值左边的子序列进行快速排序

        if (first < i - 1)

            QuickSort(r, first, i - 1);

        // 对基准值右边的子序列进行快速排序

        if (i + 1 < end)

            QuickSort(r, i + 1, end);

    }

}

int main()

{

    LineList list[MAXSIZE];

    int num, i;

    printf("请输入要排序的数据个数(小于等于 %d ):", MAXSIZE - 1);

    scanf("%d", &num);

    // 输入数据

    printf("请依次输入 %d 个整数:\n", num);

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

    {

        scanf("%d", &list[i].Key);

    }

    // 调用快速排序函数进行排序

    QuickSort(list, 0, num - 1);

    // 输出排序后的结果

    printf("排序后的结果为:\n");

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

    {

        printf("%d ", list[i].Key);

    }

    printf("\n");

    return 0;

}

4. 直接插入排序基于单链表的实现(设计实训选作)。

#include <stdio.h>

#include <stdlib.h>

// 定义链表节点结构体

typedef struct ListNode {

    int val;

    struct ListNode *next;

} ListNode;

// 创建链表节点函数

ListNode* createNode(int val) {

    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));

    newNode->val = val;

    newNode->next = NULL;

    return newNode;

}

// 直接插入排序函数,接收链表头指针

void insertionSortList(ListNode* head) {

    if (head == NULL) return;

    ListNode* sorted = head;  // 已排序部分的头指针,初始为原链表头

    ListNode* unsorted = head->next;  // 未排序部分的头指针,初始为原链表第二个节点

    sorted->next = NULL;  // 先将已排序部分初始化为只有一个节点(原链表头),且它的next设为NULL

    while (unsorted!= NULL) {

        ListNode* current = unsorted;

        unsorted = unsorted->next;

        if (current->val < sorted->val) {

            // 当前节点值小于已排序部分头节点值,将其插入到已排序部分头部

            current->next = sorted;

            sorted = current;

        } else {

            ListNode* search = sorted;

            while (search->next!= NULL && search->next->val < current->val) {

                search = search->next;

            }

            current->next = search->next;

            search->next = current;

        }

    }

    head = sorted;  // 更新原链表头指针,使其指向排好序的链表头

}

// 用于输入链表元素,构建链表

ListNode* inputList() {

    ListNode* head = NULL;

    ListNode* tail = NULL;

    int val;

    printf("请输入链表元素,输入 -1 表示结束输入:\n");

    scanf("%d", &val);

    while (val!= -1) {

        ListNode* newNode = createNode(val);

        if (head == NULL) {

            head = newNode;

            tail = newNode;

        } else {

            tail->next = newNode;

            tail = newNode;

        }

        scanf("%d", &val);

    }

    return head;

}

// 用于打印链表

void printList(ListNode* head) {

    ListNode* p = head;

    while (p!= NULL) {

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

        p = p->next;

    }

    printf("\n");

}

int main() {

    ListNode* head = inputList();

    printf("原链表: ");

    printList(head);

    insertionSortList(head);

    printf("排序后链表: ");

    printList(head);

    return 0;

}

5. 对一组数据进行双向起泡排序(按升序排列)(设计实训选作)。、

#include <stdio.h>

// 双向起泡排序函数

void bidirectionalBubbleSort(int arr[], int n) {

    int left = 0;

    int right = n - 1;

    int swapped;

    do {

        swapped = 0;

        // 从前往后比较交换,把最大元素移到后面

        for (int i = left; i < right; i++) {

            if (arr[i] > arr[i + 1]) {

                int temp = arr[i];

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

                arr[i + 1] = temp;

                swapped = 1;

            }

        }

        if (!swapped) break;  // 如果这一趟没有交换,说明已经有序,直接结束

        swapped = 0;

        right--;  // 每趟排序后,最大元素已在正确位置,缩小右边界

        // 从后往前比较交换,把最小元素移到前面

        for (int i = right; i > left; i--) {

            if (arr[i] < arr[i - 1]) {

                int temp = arr[i];

                arr[i] = arr[i - 1];

                arr[i - 1] = temp;

                swapped = 1;

            }

        }

        left++;  // 每趟排序后,最小元素已在正确位置,缩小左边界

    } while (left < right);

}

int main() {

    int n;

    printf("请输入要排序的数据个数:");

    scanf("%d", &n);

    int arr[n];

    printf("请依次输入 %d 个整数:\n", n);

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

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

    }

    bidirectionalBubbleSort(arr, n);

    // 输出排序后的数组

    printf("排序后的结果为:\n");

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

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

    }

    printf("\n");

    return 0;

}

六、实训注意事项

1.题目自选,课内至少要完成两个题目。

2.若完成题目个数多或设计的算法效率高,予以加分。

七、预习与思考题

1.直接插入排序算法思想。

2.冒泡排序算法思想。

八、实训报告要求

1.书写算法或完整程序。

2. 若调试程序时出现错误,请分析错误原因并给出解决方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值