当前位置: 首页 > news >正文

Java冒泡排序的不同实现

一、基础版冒泡排序

基础版冒泡排序是最直观的实现方式,其核心思想是重复遍历待排序数组,每次比较相邻的两个元素,若顺序错误则交换位置。

public class BubbleSortBasic {

public static void bubbleSort(int[] arr) {

if (arr == null || arr.length <= 1) {

return;

}

int n = arr.length;

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

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

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

// 交换元素

int temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

}

public static void main(String[] args) {

int[] arr = {64, 34, 25, 12, 22, 11, 90};

bubbleSort(arr);

System.out.println("排序后的数组:");

for (int num : arr) {

System.out.print(num + " ");

}

}

}

在基础版中,外层循环控制排序的轮数,内层循环负责每轮中相邻元素的比较和交换。随着每一轮的进行,最大的元素会 “浮” 到数组的末尾,所以内层循环的范围会逐渐缩小。

二、优化版冒泡排序

基础版存在一个问题:当数组在中途已经排好序时,算法仍会继续执行剩余的循环,造成不必要的开销。优化版通过引入一个标志位来解决这个问题。

public class BubbleSortOptimized {

public static void bubbleSort(int[] arr) {

if (arr == null || arr.length <= 1) {

return;

}

int n = arr.length;

boolean swapped;

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

swapped = false;

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

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

int temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

swapped = true;

}

}

// 如果本轮没有发生交换,说明数组已排好序,提前退出

if (!swapped) {

break;

}

}

}

public static void main(String[] args) {

int[] arr = {64, 34, 25, 12, 22, 11, 90};

bubbleSort(arr);

System.out.println("排序后的数组:");

for (int num : arr) {

System.out.print(num + " ");

}

}

}

优化版中添加了一个swapped标志,当某一轮循环中没有元素交换时,说明数组已经有序,此时直接跳出外层循环,大大减少了不必要的比较操作。

三、双向冒泡排序

双向冒泡排序(也称为鸡尾酒排序)在传统冒泡排序的基础上进行了改进,它不仅会将最大的元素 “浮” 到末尾,还会将最小的元素 “沉” 到开头,从而提高排序效率。

public class CocktailSort {

public static void cocktailSort(int[] arr) {

if (arr == null || arr.length <= 1) {

return;

}

int left = 0;

int right = arr.length - 1;

while (left < right) {

// 从左到右,将最大元素移到右侧

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;

}

}

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;

}

}

left++;

}

}

public static void main(String[] args) {

int[] arr = {64, 34, 25, 12, 22, 11, 90};

cocktailSort(arr);

System.out.println("排序后的数组:");

for (int num : arr) {

System.out.print(num + " ");

}

}

}

双向冒泡排序适合处理一些特定的数组,例如当最小的元素位于数组末尾时,传统冒泡排序需要多轮循环才能将其移到正确位置,而双向冒泡排序一次从右到左的遍历就能完成。

四、基于链表的冒泡排序

除了对数组进行排序,冒泡排序也可以应用于链表。基于链表的冒泡排序不需要像数组那样频繁地交换元素,而是通过调整节点的指针来实现排序。

class ListNode {

int val;

ListNode next;

ListNode(int x) {

val = x;

next = null;

}

}

public class BubbleSortLinkedList {

public static ListNode bubbleSort(ListNode head) {

if (head == null || head.next == null) {

return head;

}

ListNode end = null;

while (end != head) {

ListNode current = head;

ListNode prev = null;

while (current.next != end) {

if (current.val > current.next.val) {

// 交换节点

ListNode nextNode = current.next;

current.next = nextNode.next;

nextNode.next = current;

if (prev == null) {

head = nextNode;

} else {

prev.next = nextNode;

}

prev = nextNode;

} else {

prev = current;

current = current.next;

}

}

end = current;

}

return head;

}

public static void main(String[] args) {

ListNode head = new ListNode(64);

head.next = new ListNode(34);

head.next.next = new ListNode(25);

head.next.next.next = new ListNode(12);

head.next.next.next.next = new ListNode(22);

head.next.next.next.next.next = new ListNode(11);

head.next.next.next.next.next.next = new ListNode(90);

head = bubbleSort(head);

System.out.println("排序后的链表:");

ListNode current = head;

while (current != null) {

System.out.print(current.val + " ");

current = current.next;

}

}

}

基于链表的冒泡排序在空间复杂度上有一定优势,它不需要额外的数组空间来存储元素,只需操作指针即可。

五、各种实现方式的对比

实现方式

时间复杂度(平均)

时间复杂度(最坏)

空间复杂度

适用场景

基础版冒泡排序

O(n²)

O(n²)

O(1)

简单数组排序,数据量较小

优化版冒泡排序

O(n²)

O(n²)

O(1)

可能提前有序的数组

双向冒泡排序

O(n²)

O(n²)

O(1)

有较小元素在末尾或较大元素在开头的数组

基于链表的冒泡排序

O(n²)

O(n²)

O(1)

链表结构的数据

http://www.lryc.cn/news/597172.html

相关文章:

  • Excel自动分列开票工具推荐
  • 耐达讯自动化EtherCAT转RS232:示波器连接的“开挂秘籍”
  • IDEA如何管理多个Java版本。
  • 图机器学习(16)——图数据与自然语言处理
  • 使用idea 将一个git分支的部分记录合并到git另一个分支
  • idea部署新项目时,用自定义的maven出现的问题解决
  • 【网络编程】二、socket编程
  • Excel 将数据导入到SQLServer数据库
  • Linux文件——Ext2文件系统(3)_软硬链接
  • Encore.ts:下一代高性能 TypeScript 后端框架的崛起
  • Qt(基本组件和基本窗口类)
  • 开源深度学习新宠:Burn框架助您无忧高效建模
  • Django实战:Python代码规范指南
  • 开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端
  • Neo4j如何修改用户密码?
  • Android14 锁屏密码修改为至少6位
  • ESP32-CAM实战:DIY基于OpenAI的AI视觉识别相机
  • DeepSeek Janus Pro本地部署与调用
  • Object Sense (OSE):一款从编辑器脚本发展起来的编程语言
  • 【markdown】 VSCode 使用 Markdown Preview Enhanced 插件转PDF
  • 【前端】ikun-pptx编辑器前瞻问题三: pptx的图片如何提取,并在前端渲染。
  • Android埋点实现方案深度分析
  • 模拟实现消息队列项目
  • 音视频学习(四十三):H264无损压缩
  • 《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——3. QML入门:像搭积木一样构建UI
  • ESP32-S3学习笔记<4>:I2C的应用
  • DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_家庭维护示例(CalendarView01_31)
  • WebGIS 中常用空间数据格式
  • 2025暑期—06神经网络-常见网络3
  • 2025暑期—06神经网络-常见网络2