基于链表的简单选择排序算法实现(C语言)

引言

选择排序是一种简单直观的排序算法,它的基本思想是:每次从未排序的部分选出最小(或最大)的元素,放到已排序部分的末尾。本文将展示如何使用C语言和链表结构来实现选择排序算法。

链表节点定义

首先,我们定义链表节点的结构:

#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode {
    int val;
    struct ListNode *next;
} ListNode;

简单选择排序实现

以下是基于链表的简单选择排序实现:

ListNode* selectionSort(ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    
    ListNode *dummy = (ListNode*)malloc(sizeof(ListNode)); // 创建虚拟头节点方便操作
    dummy->next = head;
    ListNode *sortedTail = dummy;      // 已排序部分的尾部
    
    while (sortedTail->next != NULL) {
        ListNode *prev = sortedTail;   // 最小节点的前驱
        ListNode *minNode = prev->next; // 最小节点
        ListNode *curr = minNode->next; // 当前节点
        
        // 寻找最小节点
        while (curr != NULL) {
            if (curr->val < minNode->val) {
                prev = minNode;
                minNode = curr;
            }
            curr = curr->next;
        }
        
        // 将最小节点从原位置移除
        prev->next = minNode->next;
        
        // 将最小节点插入到已排序部分的末尾
        minNode->next = sortedTail->next;
        sortedTail->next = minNode;
        
        // 如果minNode是sortedTail的下一个节点,说明它已经在正确位置
        // 否则需要移动sortedTail
        if (minNode != sortedTail->next) {
            sortedTail = sortedTail->next;
        } else {
            sortedTail = minNode;
        }
    }
    
    ListNode *newHead = dummy->next;
    free(dummy);
    return newHead;
}

辅助函数

为了方便测试,我们还需要一些辅助函数:

// 创建链表
ListNode* createList(int nums[], int size) {
    ListNode *dummy = (ListNode*)malloc(sizeof(ListNode));
    ListNode *curr = dummy;
    for (int i = 0; i < size; i++) {
        curr->next = (ListNode*)malloc(sizeof(ListNode));
        curr->next->val = nums[i];
        curr->next->next = NULL;
        curr = curr->next;
    }
    ListNode *head = dummy->next;
    free(dummy);
    return head;
}

// 打印链表
void printList(ListNode *head) {
    while (head != NULL) {
        printf("%d ", head->val);
        head = head->next;
    }
    printf("\n");
}

// 释放链表内存
void deleteList(ListNode *head) {
    while (head != NULL) {
        ListNode *temp = head;
        head = head->next;
        free(temp);
    }
}

测试示例

int main() {
    int nums[] = {4, 2, 1, 3, 5};
    int size = sizeof(nums) / sizeof(nums[0]);
    ListNode *head = createList(nums, size);
    
    printf("原始链表: ");
    printList(head);
    
    head = selectionSort(head);
    
    printf("排序后链表: ");
    printList(head);
    
    deleteList(head);
    return 0;
}

输出结果:

原始链表: 4 2 1 3 5 
排序后链表: 1 2 3 4 5 

算法复杂度分析

  • 时间复杂度:O(n²)。每次寻找最小节点需要遍历剩余的未排序部分,共需要进行n-1次这样的操作。

  • 空间复杂度:O(1)。除了几个指针变量外,不需要额外的存储空间。

关键点说明

  1. 虚拟头节点:使用虚拟头节点(dummy node)可以简化链表操作,特别是在处理头节点可能变化的情况。

  2. 指针操作:链表排序的关键在于正确地操作指针,包括:

    • 找到最小节点的前驱节点(prev)

    • 将最小节点从原位置移除(prev->next = minNode->next)

    • 将最小节点插入到已排序部分的末尾

  3. 边界条件:需要特别注意链表为空或只有一个节点的情况。

总结

这个C语言实现的链表选择排序展示了指针操作的技巧性。相比数组实现的选择排序,链表版本避免了大量数据移动的开销,但增加了指针操作的复杂性。选择排序虽然时间复杂度较高,但实现简单,适合用于教学和小规模数据排序。

希望这篇博客能帮助你理解链表上的选择排序实现。如果有任何问题或建议,欢迎留言讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值