文章列表

排序算法

Champ2025.01.01 00:00访问量0 次阅读
排序算法
数据结构与算法

排序

比较排序

冒泡排序

每次遍历到尾,两两进行比较,遍历到结尾会浮出一个最值,形似冒泡,数组若有n个元素,则冒n-1次泡,最终全部排完。O(n),O(n^2),O(n^2)

void Bubblesort(int arr[],int n)
{
    for(int i=0;i<n-1;i++)
    {
        for(int j=0;j<n-i-1;j++)
        {
            if(arr[j]>arr[j+1])
            {
                int temp=arr[j+1];
                arr[j+1]=arr[j];
                arr[j]=temp;
            }
        }
    }
}

选择排序

从数组一端开始遍历,假设当前位置 ind 对应值为最小值,从下一位 ind+1 开始第二层遍历,如果在第二层遍历中找到比假设值更小的数,则交换,遍历过后能把最小的数换到 ind 的位置,整体过程上看,每趟遍历把剩下的最小值排起来,最终全部排完。O(n^2),O(n^2),O(n^2)

void SelectSort(int arr[],int n)
{
    for(int i=0;i<n-1;i++)
    {
        int ind = i;//假设最小值的下标
        for(int j=ind+1;j<n;j++)
        {
            if(arr[j] < arr[ind])
            {
                int temp = arr[ind];
                arr[ind] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

插入排序

将数据分为已排序和未排序两部分,每次取一个元素插入到已排序部分的正确位置。

O(n),O(n^2),O(n^2)

void InsertSort(int arr[],int n)
{
    for(int i=1;i<n;i++)
    {
        int key=arr[i];
        int j=i-1;
        while(j>=0 && arr[j]>key)//前面有比它大的
        {
            arr[j+1]=arr[j];//全部往后排
            j--;
        }
        arr[j+1]=key;
    }
}

快速排序

通过选择一个“基准”元素,将数组分为两部分,然后递归地对两部分进行排序。从平均时间性能而言,快速排序最佳。

O(nlogn),O(nlogn),O(n^2)

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}

int Divide(int arr[],int low,int high)//high = n-1
{
    int pivot = arr[low];
    while(low<high)
    {
        while(low<high&&arr[high]>=pivot)
        {
            high--;
        }
        if(low<high)
        {
            swap(&arr[high],&arr[low]);
        }
        while(low<high&&arr[low]<=pivot)//上面交换后自然比pivot小,直接进入while而不用手动low++
        {
            low++;
        }
        if(low<high)
        {
            swap(&arr[low],&arr[high]);
        }
    }
    return low;
}

void QuickSort(int arr[],int low,int high)
{
    if(low<high)//别忘了递归终止条件
    {
        int ind = Divide(arr,low,high);//返回中值
        QuickSort(arr,low,ind-1);//递归排序中指左右两部分
        QuickSort(arr,ind+1,high);
    }
}

归并排序

通过分治法将待排序序列分为两个子序列,递归排序后再合并两个已排序的子序列。

O(nlogn),O(nlogn),O(nlogn),开辟数组以空间换时间,不受数据初始情况的影响

void MergeSort(int arr[], int l, int r)
{
    if (l < r)//递归终止条件
    {
        int mid = l + (r - l) / 2;
        int n1 = mid - l + 1; // 左部分长度
        int n2 = r - mid;     // 右部分长度
        int L[n1], R[n2];

        //递归调用左右部分
        MergeSort(arr,l,mid);
        MergeSort(arr,mid+1,r);

        // 赋值
        for (int i = 0; i < n1; i++)
        {
            L[i] = arr[l + i];
        }
        for (int i = 0; i < n2; i++)
        {
            R[i] = arr[mid + i + 1];
        }

        
        //比较并合并
        int i = 0, j = 0, k = l;
        while (i < n1 && j < n2)
        {
            if (L[i] < R[j])
            {
                arr[k] = L[i];
                i++;
            }
            else
            {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
        // 剩余元素
        while (i < n1)
        {
            arr[k] = L[i];
            i++;
            k++;
        }
        while(j<n2)
        {
            arr[k] = R[j];
            j++;
            k++;
        }
    }
}

堆排序

通过将数据构建成一个堆结构(通常是二叉堆),然后不断取出堆顶元素,并调整堆。

O(n),O(nlogn),O(nlogn)

  • 建堆

从最后一个非叶子节点(下标为 n/2-1 )开始,倒着检查该节点是否是子树的根,如果不是就调整(与子树中最大值互换,如3号节点和7号节点,注意,如果7号节点还有子树,交换后还需递归判断交换后子树是否是堆)。

  • 排序

将堆顶元素与堆底元素进行交换,使旧堆顶元素归位,再对新堆顶进行调整建堆

  • 下标从0开始的堆代码

    void buildHeap0(int arr[],int n,int top)
    {
        int largest=top;
        //base on zero 
        int left=top*2+1;
        int right=top*2+2;
        if(left<n&&arr[left]>arr[largest])
        {
            largest=left;
        }
        if(right<n&&arr[right]>arr[largest])
        {
            largest=right;
        }
        
        if(largest!=top)
        {
            int temp=arr[largest];
            arr[largest]=arr[top];
            arr[top]=temp;
    
            //don't forget to adjust
            buildHeap0(arr,n,largest);
        }
    }
    
    void heapSort0(int arr[],int n)
    {
        for(int i=n/2-1;i>=0;i--)
        {
            buildHeap0(arr,n,i);//from bottom to top
        }
        for(int i=n-1;i>0;i--)//don't have to deal with the last one
        {
            int temp=arr[i];
            arr[i]=arr[0];
            arr[0]=temp;
    
            buildHeap0(arr,i,0);//i:隐藏换到底部的最大值
        }
    }
    
    
  • 下标从1开始的

    //最大堆
    void buildHeap(int arr[],int n,int top)
    {
        int left=top*2;
        int right=top*2+1;
        int largest=top;
        if(left<=n&&arr[left-1]>arr[largest-1])
        {
            largest=left;
        }
        if(right<=n&&arr[right-1]>arr[largest-1])
        {
            largest=right;
        }
        if(top!=largest)//如果当前堆顶不是最大的
        {
            int temp=arr[top-1];
            arr[top-1]=arr[largest-1];
            arr[largest-1]=temp;
    
            //别忘了交换后还要调整子树
            buildHeap(arr,n,largest);
        }
    }
    
    void headSort(int arr[],int n)
    {
        for(int i=n/2;i>=1;i--)
        {
            buildHeap(arr,n,i);//从下到上构建堆
        }
    
        for(int i=n;i>=2;i--)
        {
            int temp=arr[i-1];
            arr[i-1]=arr[0];
            arr[0]=temp;
    
            //调整堆
            buildHeap(arr,i-1,1);
        }
    }
    

非比较排序

基数排序

按照元素的位数进行排序,每次排序时根据某一位数的值对数据进行排序,依次处理每一位。

O(d(n+rd)) , O(d(n+rd)) , O(d(n+rd))

分为最低位优先法(LSD)和最高位优先法(MSD)

第一趟排序(个位):

桶排序

计数排序

其他排序

希尔排序(插入排序改进版)

O(n^3/2) — O(n^7/6)

Tim sort

排序算法性能一览

历史留言 (0)
ICP备案号浙ICP备2026065730号-1公安备案号浙公网安备33019202003213号