* 冒 泡 排 序 (Bubble Sort)*
关键思想
顺序依次比较相邻两个元素,倒序则交换。
时间复杂度
Time Complexity | Value |
---|---|
最优时间复杂度 | O ( n ) O(n) O(n) |
最差时间复杂度 | O ( n 2 ) O(n^{2}) O(n2) |
平均时间复杂度 | O ( n 2 ) O(n^{2}) O(n2) |
解析:
1)最优时间复杂度:输入序列( n u m = n num=n num=n)自身顺序时,仅需一轮 n − 1 n-1 n−1次比较便可结束。
2)最差时间复杂度:输入序列( n u m = n num=n num=n)自身倒序时,一共需要经过 n − 1 n-1 n−1轮才可结束。具体而言,即第 i i i轮冒泡排序需比较 n − i n-i n−i次,交换 3 ( n − i ) 3(n-i) 3(n−i)次,则共需比较 ∑ i = 1 n − 1 = n ( n − 1 ) 2 \displaystyle\sum_{i=1}^{n-1}=\frac {n(n-1)} 2 i=1∑n−1=2n(n−1)次,交换 3 ∑ i = 1 n − 1 = 3 n ( n − 1 ) 2 3\displaystyle\sum_{i=1}^{n-1}=3\frac {n(n-1)} 2 3i=1∑n−1=32n(n−1)次。
空间复杂度
Space Complexity | Value |
---|---|
空间复杂度 | O(1) |
稳定性 √
解析:
稳定性:若原序列中数 i i i位于数 j j j前面,且 i = j i=j i=j,整个排序过程结束之后数 i i i仍位于数 j j j前面。
实例:[6 3 8 2 9 1](Java)
public static void main(String[] args) {
// TODO 自动生成的方法存根
System.out.println("请键盘输入整数序列[例如:6 3 8 2 9 1 end]"); // 从键盘接收输入信息
Scanner list = new Scanner(System.in);
ArrayList<Integer> inputArray = new ArrayList<Integer>();
while (list.hasNextInt()) {
inputArray.add(list.nextInt());
} // 输入--非数字--结束输入过程
list.close();
System.out.println("输入:" + inputArray);
// End2Start(inputArray); // Case1: start ← end
// Start2End(inputArray); // Case2: start → end
End2StartImprove(inputArray); // Case3: start ← end[优化]
}
Case1:左 ← 右(从小到大排序)
// Case1: start ← end
public static void End2Start(ArrayList<Integer> inputArray) {
for (int i = 0; i < inputArray.size() - 1; i++) {
System.out.println("第" + (i + 1) + "轮" + "冒泡排序");
for (int j = inputArray.size() - i - 1; j > 0; j--) {
if (inputArray.get(j) < inputArray.get(j - 1)) {
System.out.print(inputArray.get(j) + "<" + inputArray.get(j - 1) + " → 交换 → ");
int temp = inputArray.get(j);
inputArray.set(j, inputArray.get(j - 1));
inputArray.set(j - 1, temp);
System.out.println(inputArray);
}
else
System.out.println(inputArray.get(j) + ">" + inputArray.get(j - 1) + " → 不交换 → " + inputArray);
}
System.out.println("End:" + inputArray);
}
System.out.println("输出:" + inputArray);
}
Case2:左 → 右(从小到大排序)
// Case2: start → end
public static void Start2End(ArrayList<Integer> inputArray) {
for (int i = 0; i < inputArray.size() - 1; i++) {
System.out.println("第" + (i + 1) + "轮" + "冒泡排序");
for (int j = 0; j < inputArray.size() - i - 1; j++) {
if (inputArray.get(j) > inputArray.get(j + 1)) {
System.out.print(inputArray.get(j) + ">" + inputArray.get(j + 1) + " → 交换 → ");
int temp = inputArray.get(j);
inputArray.set(j, inputArray.get(j + 1));
inputArray.set(j + 1, temp);
System.out.println(inputArray);
}
else
System.out.println(inputArray.get(j) + "<" + inputArray.get(j + 1) + " → 不交换 → " + inputArray);
}
System.out.println("End:" + inputArray);
}
System.out.println("输出:" + inputArray);
}
Case3:左 ← 右【优化】(从小到大排序)
思考:某一轮冒泡排序过程中无任何交换时,说明已经有序,结束。
1)Case1[6 3 8 2 9 1]:第4轮冒泡排序过程开始已无交换过程;
2)Case2[6 3 8 2 9 1]:最后一轮冒泡排序过程依旧包含交换过程;
3)Case1与Case2[6 3 8 2 9 1]:总交换次数相等,总比较次数相等。
结论:优化只针对Case1有效!
// Case3: start ← end[优化]
public static void End2StartImprove(ArrayList<Integer> inputArray) {
int i = 0;
boolean change = false;
do
{
change = true;
System.out.println("第" + (i + 1) + "轮" + "冒泡排序");
for (int j = inputArray.size() - i - 1; j > 0; j--) {
if (inputArray.get(j) < inputArray.get(j - 1)) {
System.out.print(inputArray.get(j) + "<" + inputArray.get(j - 1) + " → 交换 → ");
int temp = inputArray.get(j);
inputArray.set(j, inputArray.get(j - 1));
inputArray.set(j - 1, temp);
System.out.println(inputArray);
change = false;
}
else
System.out.println(inputArray.get(j) + ">" + inputArray.get(j - 1) + " → 不交换 → " + inputArray);
}
i++;
System.out.println("End:" + inputArray);
}
while((i < inputArray.size() - 1) && (change == false));
System.out.println("输出:" + inputArray);
}