面试排序算法总结

冒泡排序

  冒泡排序是最基础的排序算法了,大体的思想是通过与相邻元素的比较和交换把小的数交换到最前面。不断的重复交换的过程,直到有一轮遍历没有发生交换。冒泡排序的时间复杂度为$O(n^{2})$。

  代码如下:

class BubbleSort
{
public:
    void bubbleSort(vector<int>& arr)
    {
        if(arr == null || arr.length == 0)
            return ;
        for(int i=0; i<arr.size()-1; i++)
        {
            int flag = 0;       
            for(int j=arr.size()-1; j>i; j--)
            {
                if(arr[j] < arr[j-1])
                {
                    swap(arr, j-1, j);
                    flag = 1;
                }
            }
            if(flag == 0) break;
        }
    }

    void swap(vector<int>& arr, int i, int j)
    {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

选择排序

  大致思想和冒泡一致,一次排序之后把最小的值放在最前面,但是过程不同。选择排序一次遍历的时候找到除了起始位置之外最小的值,然后考虑是否与其实位置的值交换。时间复杂度为$O(n^{2})$。代码如下:

  

class SelectSort
{

public:
    void selectSort(vector<int>& arr)
    {
        if(arr == null || arr.size() == 0)
            return ;
        int minIndex = 0;
        for(int i=0; i<arr.size()-1; i++)   //只需要比较n-1次
        {
            minIndex = i;
            for(int j=i+1; j<arr.size(); j++)   //从i+1开始比较,因为minIndex默认为i了,i就没必要比了。
            {
                if(arr[j] < arr[minIndex])
                {
                    minIndex = j;
                }
            }
            if(minIndex != i)   //如果minIndex不为i,说明找到了更小的值,交换之。
            {
                swap(arr, i, minIndex);
            }
        }

    }
    void swap(vector<int>& arr, int i, int j)
    {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

插入排序:

  依次枚举数组的每个index,在枚举的时候保证index之前的数是有序的。在枚举到i的时候,有序的插入到[0,i-1]子数组中,重复上述步骤即可。代码如下:

  

void insertSort(vector<int>& arr)
    {
        if(arr == null || arr.size() == 0)
            return ;

        for(int i=1; i<arr.size(); i++)   //假设第一个数位置时正确的;要往后移,必须要假设第一个。
        {

            int j = i;
            int target = arr[i]; //待插入的

            //后移
            while(j > 0 && target < arr[j-1])
            {
                arr[j] = arr[j-1];
                j --;
            }

            //插入
            arr[j] = target;
        }

    }

快速排序:

  快速排序可以理解为冒泡排序的一个改进,冒泡排序是通过相邻元素的比较和交换把最小的冒泡到最顶端,而快速排序是比较和交换小数和大数,这样一来不仅把小数冒泡到上面同时也把大数沉到下面。

  举个栗子:对$5,3,8,6,4$这个无序序列进行快速排序,思路是右指针找比基准数小的,左指针找比基准数大的,交换之。

  $5,3,8,6,4$ 用5作为比较的基准,最终会把5小的移动到5的左边,比5大的移动到5的右边。

  $5,3,8,6,4$首先设置$i,j$两个指针分别指向两端,$j$指针先扫描4比5小停止。然后$i$扫描,8比5大停止。交换$i,j$位置。

  $5,3,4,6,8$然后$i$指针再扫描,这时j扫描4时两指针相遇。停止。然后交换4和基准数。

  $4,3,5,6,8$ 一次划分后达到了左边比5小,右边比5大的目的。之后对左右子序列递归排序,最终得到有序序列。

  

int Partition(vector<int>& arr,int left,int right)
{
   int tmp = arr[left];
   while(left < right)
   {
       while(left < right && arr[right] >= tmp) right--;
       arr[left] = arr[right];
       while(left < right && arr[left] <= tmp) left++;
       arr[right] = arr[left];
   }
   arr[left] = tmp;
   return left;
}

void quickSort(vector<int>& arr, int left, int right)
{
    if(left >= right)
        return ;
    int pivotPos = Partition(arr, left, right);
    quickSort(arr, left, pivotPos-1);
    quickSort(arr, pivotPos+1, right);
}

堆排序:

  简单说一下堆排序的基本思路:

  a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

  b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

  c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

  简单说明一下如何条件结构,首先找到最后一个非叶子节点(这里用数组模拟树的化,第一个非叶子节点为arr.size()-1),从左至右,从上到下调整。例如对于初始的状态:

  

   我们从index = 1的节点开始调整:

  这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

   这样一个大根堆就调整好了。之后不断的将末尾的数换至数组起始位置进行调整就好了,代码如下:

class HeapSort
{

    publicvoid Sort(vector<int>& arr)
    {
        //1.构建大顶堆
        for(int i=arr.size()/2-1; i>=0; i--)
        {
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr,i,arr.size());
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for(int j=arr.size()-1; j>0; j--)
        {
            swap(arr,0,j);//将堆顶元素与末尾元素进行交换
            adjustHeap(arr,0,j);//重新对堆进行调整
        }

    }

    /**
     * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
     * @param arr
     * @param i
     * @param length
     */
    void adjustHeap(vector<int>& arr,int i,int length)
    {
        int temp = arr[i];//先取出当前元素i
        for(int k=i*2+1; k<length; k=k*2+1) //从i结点的左子结点开始,也就是2i+1处开始 不断的向下调整
        {
            if(k+1<length && arr[k]<arr[k+1]) //如果左子结点小于右子结点,k指向右子结点
            {
                k++;
            }
            if(arr[k] >temp) //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
            {
                arr[i] = arr[k];
                i = k;
            }
            else
            {
                break;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
    }

    /**
     * 交换元素
     * @param arr
     * @param a
     * @param b
     */
    void swap(int []arr,int a,int b)
    {
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

希尔排序:

(待整理)  

归并排序:

  

https://www.cnblogs.com/wxisme/p/5243631.html

  

原文地址:https://www.cnblogs.com/z1141000271/p/12771479.html