zoukankan      html  css  js  c++  java
  • 冒泡排序与两数交换的实现与优化

    冒泡排序与两数交换的实现与优化

    By: 大志若愚

      冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
         它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
         这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端,故名。

    过程图:

     

    (一)标准版本:未优化版本

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace 冒泡排序
    {
        class Program
        {
            static void Main(string[] args)
            {
                int[] array = {9,1,2,3,4,5,6,7,8,0};
                array = BubbleSort01(array);
                foreach (int item in array)
                {
                    Console.Write(item + " ");
                }
                Console.ReadKey();
            }
            /// <summary>
            /// 从大到小排序
            /// </summary>
            /// <param name="array">要进行冒泡排序的数组</param>
            /// <returns>排序后的数组</returns>
            private static int[] BubbleSort01(int[] array)
            {
                for (int i = 0; i < array.Length - 1; i++)
                {
                    for (int j = 0; j < array.Length -1 - i; j++)
                    {
                        if (array[j] < array[j + 1])
                        {
                            Swap01(ref array[j], ref array[j + 1]);
                        }
                    }
                }
                return array;
            }
         // 实现二数交换,下面有其他方式的解释       
         
    private static void Swap01(ref int num1,ref int num2) { int temp; temp = num1; num1 = num2; num2 = temp; } } }

      (2)设置单标志:优化版本一

      标志:用于标志每趟循环是否有数进行了交换,若无,则数组已实现排序 

    private static int[] BubbleSort02(int[] array)
    {
        bool flag = true;
        int n = array.Length - 1;
        while (flag)
        {
            flag = false;
            for (int i = 0; i < n - 1; i++)
            {
                if (array[i] < array[i + 1])
                {
                    //Swap01(ref array[i], ref array[i + 1]);
                    //Swap02(ref array[i], ref array[i + 1]);
                    Swap03(ref array[i], ref array[i + 1]);
                    flag = true;
                }
            }
            n--;
        }
        return array;
    }

      flag用于标志每趟循环是否有数进行交换[即是否仍乱序],若为true,则标志数组还未有序。

    (3)设置双标志:优化版本二

      标志一:用于标志每趟循环是否有数进行了交换,若flag=0,则数组已实现排序

      标志二:若循环有数进行了交换,标志最后一次交换的位置,标志之后的则已经有序

    private static int[] BubbleSort03(int[] array)
    {
        int k;
        int flag = array.Length - 1;
        while (flag > 0)
        {
            k = flag;
            flag = 0;
            for (int i = 0; i < k; i++)
            {
                if (array[i] < array[i + 1])
                { 
                    Swap03(ref array[i], ref array[i + 1]);
                    flag = i;
                }
            }            
        }           
        return array;
    }

      flag用于标志每趟循环是否有数进行交换[即是否仍乱序],若为大于0,则标志数组还未有序。

      增加了k来标志在这之前仍需要排序位置,在k之后的则已经有序。

    实现两数交互:

      我想在这里说下,实现两数交互的实现

    (1)一般做法,利用第三方变量,同时因为int,enum,struct典型的值类型,需要进行引用传值

    private static void Swap(ref int num1,ref int num2)
    {       int temp = num1;
        num1 = num2;
        num2 = temp;
    }

    不使用第三方变量实现:解方程,异或

     (2)  解方程式:[名字可以随意,自己可以取个好记忆的]

     private static void Swap(ref int num1, ref int num2)
    {
        num1 = num1 - num2;
        num2 = num1 + num2;
        num1 = num2 - num1;
    }

    但是这种方式引入了一个陷阱,如果num1是一个很大的正数而num2是一个很大的负数,那么num1-num2就会溢出。虽然在num2=num1+num2时可能会通过再一次溢出从而获得真实的num1的值,不推荐这种利用未定义行为的解法

    如何理解这种解法?其实第一行是num1=num1-num2还是num1=num1+num2再或者是num1=num1*num2都可以,对应地在第二行把num2通过这个式子和num2本身的运算求出num1即可,再在第三行利用num1、num2的组合值以及原先的num1求解num2。明显地,使用*比+或-更容易溢出。理解后,完全不必死记硬背这三个式子,看成是解方程就不难了。

     (3)XOR[异或]

    private static void Swap03(ref int num1, ref int num2)
    {
        num1 = num1 ^ num2;
        num2 = num2 ^ num1;
        num1 = num2 ^ num1;
    }

    异或的性质:

      (1) X^0 = X 且 X^X = 0

      (2)交换律: X^Y  = Y^X 

      (3)结合律: (X^Y)^Z = X^(Y^Z)

      (4)自反性: X^Y^Y = X

      所以,这个也会出现一个问题:int x = 10; Swap(ref x, int ref x); 就会出现为x = 0的情况,对此我认为是因为由于对x的引用导致的,在交换过程中: num1 = num1 ^ num2;使得num1 = 0;而num2与num1都是对x的引用,Swap过程中,就没有保存临时计算产生的数据以及原数据,所以导致num1、num2都成为了0。

      交换两个相等的数据是没问题的,比如 int x = 8; int y = 8; Swap03(ref x ,ref y);完全是没有问题的。

      一般交换数据不会自己和自己交换数据,但是有时会出现例外,建议交换数据前进行判断是否相等,相等则比进行交换。

    private static void Swap04(ref int num1, ref int num2)
    {
        if(num1 != num2)
        {
            num1 = num1 ^ num2;
            num2 = num2 ^ num1;
            num1 = num2 ^ num1;
        }
    }
  • 相关阅读:
    网格走法数目
    字典序(数据字典)
    异或(数据字典)
    头条校招
    Python中的zip()
    什么是“背书”
    求十进制整数的任意进制转换
    安装并使用pyecharts库(0.5.10)
    pycharm使用Ctrl+滚轮调整字体大小
    Anaconda中安装pyecharts
  • 原文地址:https://www.cnblogs.com/liushen/p/3375323.html
Copyright © 2011-2022 走看看