数据结构与算法-冒泡算法

628 阅读1分钟

1,冒泡算法实现

冒泡算法是最简单的排序算法。

冒泡算法原理:从左到右相临的元素进行比较,前一个元素比后一个元素大,就进行交换。每遍历一轮就会找到元素里的最大值,交换到最右边的位置。

//c语言代码
    int array[] = {99,33,2,96,55,66,75,7,23};
    int length;
    int temp;
    length = sizeof(array) / sizeof(array[0]);
    for (int end = length - 1; end > 0; end --) {
        for (int begain = 1; begain <= end; begain ++) {
            if (array[begain] < array[begain - 1]) {
                temp = array[begain];
                array[begain] = array[begain -1];
                array[begain - 1] = temp;
            }
        }
    }

//Java代码
int array[] = {22,45,32,1,88,77,98,56,54,34,21};        
for(int end = array.length - 1; end > 0; end --){            
   for(int begain = 1; begain <= end; begain ++){                
       if(array[begain] < array[begain - 1]){                    
            int temp = array[begain];                    
            array[begain] = array[begain - 1];                    
            array[begain - 1] = temp;                
       }           
   }        
}

1.1,冒泡算法-优化1

如果冒泡算法的序列是完全有序的时候,就没必要不断的比较,可以提前终止冒泡排序。

//Java代码

         //有序数组
        int array[] = {2,4,5,7,8,17,22,26,34,44,45,49,50,51,57,58,59};
        for(int end = array.length - 1; end > 0; end --){
            //记录后一个序列是否比前一个大 
            boolean sorted = true;            
            for(int begain = 1; begain <= end; begain ++){                
                if(array[begain] < array[begain - 1]){                    
                    int temp = array[begain];                    
                    array[begain] = array[begain - 1];                    
                    array[begain - 1] = temp;                    
                    sortedIndex = begain;                    
                    sorted = false;                
                }            
            }            
            //如果都是比前一个大,break            
            if (sorted) break;        
        }

1.2,冒泡算法-优化2

如果序列的尾部已经出现了局部的有序,我们可以记录最后一次交换的位置,减少比较次数。

//Java代码
    //尾部的序列是有序的        
    int array[] = {22,45,32,1,88,77,32,56,54,34,21,90,93,95,97,98,99};        
    for(int end = array.length - 1; end > 0; end --){            
        //记录最1次交换的位置            
        int sortedIndex = 1;            
        for(int begain = 1; begain <= end; begain ++){                
            if(array[begain] < array[begain - 1]){                    
                int temp = array[begain];                    
                array[begain] = array[begain - 1];                    
                array[begain - 1] = temp;                    
                //最后1次交换的位置                    
                sortedIndex = begain;                
            }            
         }            
         end = sortedIndex;        
    }

1.3,冒泡排序的复杂度

  • 最坏,平均时间复杂度:O(n²)

  • 最好的时间复杂度:O(n)

  • 空间复杂度:O(1)

2,排序算法的稳定性

2.1,如果相等的两个元素,在排序前后的相对位置保持不变,那么这就是稳定的排序。

  • 排序前:5, 1, 3(1), 4, 6, 3(2)

  • 稳定的排序:1, 3(1), 3(2), 4, 5, 6

  • 不稳定的排序:1, 3(2), 3(1), 4, 5, 6

2.2,对自定义的对象进行排序是,稳定性会影响到最终的结果。

  • 当排序是一对多进行的时候,比如张三和小明的成绩是一样的时候,是否是稳定排序就会影响到结果  
  • 冒泡排序是稳定的排序算法

3,原地算法

3.1,何为原地算法?

  • 不依赖额外的资源或者依赖少数的额外资源,仅依靠输出来覆盖输入的称为原地算法。
  • 空间复杂度为O(1) 的都可以认为是原地算法
  • 非原地算法:Not-in-place 或 Out-of-place
  • 冒泡算法属于:In-place

4,选择排序

4.1,执行流程

  1. 从元素里面找出最大的那个元素,然后将最大的元素与最末尾位置的元素进行交换。执行完一轮以后,最末尾位置的元素就是最大的。

  2. 忽略 1 中找到的最大的元素,重复执行步骤 1。

  3. 选择排序的交换次数远小于冒泡排序,选择排序的平均性能高于冒泡排序。

  4. 代码如下

        int array[] = {22,45,32,1,88,77,32,56,54,34,21,90,93,95,97,98,99};            
        for(int end = array.length - 1; end > 0; end --){            
            //记录最大值的下标            
            int max = 0;            
            for(int begain = 1; begain <= end; begain ++){                
                if(array[max] < array[begain]){                    
                    //获取最大值的下标                    
                    max = begain;                
                }            
             }           
             //将最大值与末尾位置进行交换            
            int temp = array[end];            
            array[end] = array[max];            
            array[max] = temp;       
         }
    

4.2,复杂度

  • 最好,最坏,平均时间复杂度:O(n²)
  • 空间复杂度:O(1)
  • 属于不稳定排序

4.3,选择排序的优化

  • 可以使用堆排序来进行优化
  • 堆排序可以认为是对选择排序的一种优化

5,堆排序

5.1,执行流程

  1. 对原来的序列进行原地建堆。
  2. 重复执行以下步骤,直到堆的元素数量为 1 。
  3. 交换堆顶的元素与尾元素。
  4. 堆的元素数量减 1 。
  5. 对 0 的位置进行siftDown操作

5.2,代码实现

public class duiDemo {
    static int heapSize;    
    static int[] array;    

    public static void main(String[] args) {
        int arr[] = { 22, 45, 32, 1, 88, 77, 32, 56, 54, 34, 21, 90, 93, 95, 97, 98, 99 };        
        array = arr;  
      
        //原地建堆        
        heapSize = array.length;        
        for (int i = (heapSize >> 1) - 1; i >= 0; i--) {           
             siftDown(i);        
        }

        while (heapSize > 1){            
            //交换堆顶元素和尾部元素            
            swap(0, --heapSize);
            // 对0位置进行siftDown(恢复堆的性质)            
            siftDown(0);        
        }

        for (int i = 0; i < array.length; i++) {            
            System.out.print(array[i] + "-");        
        }
        System.out.print("hello java");

    }

    public static void siftDown(int index) {        
        int element = array[index];        
        int half = heapSize >> 1;        
        while (index < half){ //index必须是非叶子节点            
            //默认是左边跟父节点比            
            int childIndex = (index << 1) + 1;            
            int child = array[childIndex];            
            int rightIndex = childIndex + 1;            
            //又子节点比左子节点大            
            if (rightIndex < heapSize && cmp(array[rightIndex], child) > 0){                
                child = array[childIndex = rightIndex];            
            }             
            //大于等于子节点            
            if (cmp(element, child) >= 0) break;            
            array[index] = child;            
            index = childIndex;        
        }        
        array[index] = element;    
    }        

    /*     
     * 返回值等于0,代表 v1 == v2     
     * 返回值小于0,代表 v1 < v2     
     * 返回值大于0,代表 v1 > v2     
     */    
    static int cmp(int v1, int v2) {        
        return v1 - v2;    
    }

    /*     
     * 数组交换     
     */    
    static void swap(int i1, int i2) {        
        int tmp = array[i1];        
        array[i1] = array[i2];        
        array[i2] = tmp;    
    }}

5.3,复杂度

  • 最好,最坏,时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
  • 属于不稳定排序