【算法】排序算法总结

常见的排序算法汇总(详解篇) 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] 在 r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排序算法是稳定的;否则称为不稳定的。数据元素全部放在内存中的排序。数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。 阅读详情


内排序

一、插入排序

插入排序包括:直接插入排序和希尔排序

1.1 直接插入排序

算法思想:

直接插入排序是一种简单的插入排序法,其基本思想是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

用一个形象的比喻:摸牌与插牌。
在这里插入图片描述
下面进行动图演示
请添加图片描述


算法的代码实现

在这里插入图片描述

void insert_sort(int a[], int n)
{
    // tmp表示要插入的元素
    // end表示已插入元素最后一个元素的下标
    int tmp, end;
    // 1个元素默认有序,因此从1开始
    for (int i = 1; i < n; i++)
    {
        tmp = a[i];
        end = i - 1;
        while (end >= 0)
        {
            // 1. 如果a[end] > tmp, 则a[end]向后移, end--
            // 如果a[end] <= tmp,则a[end+1] = tmp
            // 特殊情况:如果tmp是最小的数,则end = -1会跳出循环,因此在循环体外赋值
            if (a[end] > tmp)
            {
                a[end + 1] = a[end];
                end--;
            }
            else
            {
                break;
            }
        }
        a[end + 1] = tmp;
    }
}

算法评价:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高

  2. 时间复杂度:O(N^2)

  3. 空间复杂度:O(1),它是一种稳定的排序算法

  4. 稳定性:稳定

改进:插入排序效率的重点:减少比较的次数,如何减少比较的次数?2的方向

  1. 快速定位新插入的元素在已排序好的位置 --> 折半查找

  2. 让原来的序列趋近于有序 --> 希尔排序

1.2 折半插入排序

算法思想

直接插入排序中将无序区的开头元素Ri插入到有序区 R[0…i-1]是采用顺序比较的方法。由于有序区的元素是有序的,可以采用折半查找方法先在R0…i-1中找到插入位置,再通过移动元素进行插入,这样的插入排序称为折半插入排序(binary insertion sort)或二分插人排序

算法实现

void mid_insert_sort(int a[], int n)
{
    int tmp, end;
    for(int i = 1; i < n; i++)
    {
        tmp = a[i];
        end = i-1;
        // 1. 折半查找位置 -- 注意稳定性,令 <= 为l区域
        int l = -1, r = i;
        while(l+1 != r)
        {
            int mid = l + r >> 1;
            if(a[mid] > tmp) r = mid;
            else l = mid;
        }
        // 2. 后移元素,[0 l] [r i-1], l+1的地方插入,后移[l+1, i-1]一位
        while(end >= l+1)
        {
            a[end+1] = a[end];
            --end; 
        }
        a[l+1] = tmp;
    }
}

算法评价

折半插入排序的元素移动次数与直接插入排序相同,不同的仅是变分散移动为集中移动。在R0…i-1中查找插入R[]的位置,折半查找的平均关键字比较次数约为log(i+1)-1,平均移动元素的次数为i/2+2,所以平均时间复杂度为:

在这里插入图片描述
实际上,折半插入排序和直接插入排序相比移动元素的性能没有改善,仅仅减少了关键字的比较次数。就平均性能而言,由于折半查找优于顺序查找,所以折半插入排序也优于直接插入排序。折半插入排序的空间复杂度为(1),也是一种稳定的排序方法。

1.3 希尔排序

算法思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有数据分成gap个组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行排序。然后,取 gap = gap/2,重复上述分组和排序的工作。当到达gap=1时,数据将排好序.

请添加图片描述
算法实现

//单组排完,在排下一组
void shell_sort(int a[], int n)
{
    int gap = n;
    while (gap > 1)
    {
        gap /= 2;
        //gap /= 3 + 1;
        //1. 分组
        for (int i = 0; i < gap; i++)
        {
            // 2. 单组插入排序
            int tmp, end;
            for (int j = i+gap; j < n; j += gap)
            {
                tmp = a[j];
                end = j - gap;
                while (end >= i)
                {
                    if (a[end] > tmp)
                    {
                        a[end + gap] = a[end];
                        end -= gap;
                    }
                    else break;
                }
                a[end+gap] = tmp;
            }
        }
    }
}
//多组并行
void shell_sort(int a[], int n)
{
    int gap = n;
    while (gap > 1)
    {
        gap /= 2;
        //多组并行
        for (int i = 0; i + gap < n; i++)
        {
            int tmp = a[i + gap];
            int end = i;
            while (end >= 0)
            {
                if (a[end] > tmp)
                {
                    a[end + gap] = a[end];
                    end -= gap;
                }
                else break;
            }
            a[end + gap] = tmp;
        }
    }
}

算法评价

希尔排序的空间复杂度:O(1)

希尔排序的时间复杂度:
在这里插入图片描述
在这里插入图片描述
希尔排序法是一种不稳定的排序算法。例如,若希尔排序分为{3,10,7,8,20}和(5,8,2,1,6)两组,显然第1组的8排列在第2组的8的后面,两组采用直接插入排序后的结果为(3,7,8,10,20}和{1,2,5,6,8),这样第1组的8排列到第2组的8的前面,它们的相对位置发生了改变。


二、选择排序

2.1 简单选择排序

算法思想

每次从剩余数中选出最小的数,与已排序的数组后面一个元素换位置

请添加图片描述
算法实现

//原版 -- 每次选出最小
void select_sort(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        int Min_i = i;
        // 1. 单趟找最小元素的下标
        for (int j = i; j < n; j++)
        {
            if (a[Min_i] > a[j])
            {
                Min_i = j;
            }
        }
        // 2. 与i下标对应的元素交换
        std::swap(a[Min_i], a[i]);
    }
}
//优化版 -- 每次选出最大和最小
void select_sort(int a[], int n)
{
    int l = 0, r = n - 1;
    while(l < r)
    {
        int Min_i = l, Max_i = r;
        // 1. 单趟找最小和最大元素的下标
        for (int j = l; j <= r; j++)
        {
            if (a[Min_i] > a[j])
            {
                Min_i = j;
            }
            if (a[Max_i] < a[j])
            {
                Max_i = j;
            }
        }
        // 2. 与l,r下标对应的元素交换
        std::swap(a[Min_i], a[l]);
        //存在情况:l指向的数就是目前区间的最大值
        if (l == Max_i)
        {
            Max_i = Min_i;
        }
        std::swap(a[Max_i], a[r]);
        l++, r--;
    }
}

算法评价

显然,无论初始数据序列的状态如何,在第i趟排序中选出最小关键字的元素,内for循环需做n-1-(i+1)+1-n-i-1次比较,因此总的比较次数为:

在这里插入图片描述
另外,简单选择排序算法是一个不稳定的排序方法。例如排序序列为(5,3,2,5,4,1,8,7),第1趟排序时选择出最小关键字1,将其与第1个位置上的元素交换,得到(1,3,2,5,4,5,8,7},从中看到两个5的相对位置发生了改变。

2.2 堆排序

算法思想

堆排序(heap sort)是一种树形选择排序方法,它的特点是将 R[1…n](R[i]的关键字为
k;)看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的位置关系在无序区中选择关键字最大(或最小)的元素。

算法实现

void AdjustDown(int a[], int n, int father)
{
    //1. 找左孩子
    int left = 2 * father + 1;
    while (left < n)
    {
        int Maxchild = left;
        //2. 找右孩子
        if (left + 1 < n && a[Maxchild] < a[left + 1]) Maxchild = left + 1;
        //3. 与父亲比较
        if (a[Maxchild] > a[father])
        {
            std::swap(a[Maxchild], a[father]);
            father = Maxchild;
            left = 2 * father + 1;
        }
        else return;
    }
}
void heap_sort(int a[], int n)
{
    for (int i = n / 2; i >= 0; i--)
    {
        AdjustDown(a, n, i);
    }
    
    for (int i = 0; i < n - 1; i++)
    {
        std::swap(a[0], a[n - 1 - i]);
        AdjustDown(a, n-1-i, 0);
    }
}

算法评价

堆排序的时间主要由建立初始堆和反复重建堆这两部分的时间构成

建堆:O(n)

排序:O(nlogn)

综上所述,堆排序的最坏时间复杂度为O(nlogn)。堆排序的平均性能分析较难,但实验研究表明,它较接近最坏性能。实际上,堆排序和简单选择排序算法一样,其时间性能与初始序列的顺序无关,也就是说,堆排序算法的最好、最坏和平均时间复杂度都是O(nlogn)。由于建初始堆所需的比较次数较多,所以堆排序不适合元素数较少的排序表,堆排序只使用i、i、tmp等辅助变量,其辅助空间复杂度为(1)。另外,在进行筛选时可能把后面相同关键字的元素调整到前面,所以堆排序算法是一种不稳定的排序方法。


三、交换排序

3.1 冒泡排序

算法思想

冒泡排序(bubble sort)也称为气泡排序,是一种典型的交换排序方法,其基本思想是通过无序区中相邻元素关键字间的比较和位置的交换使关键字最小/最大的元素如气泡一般逐渐往上“漂浮”直至“水面”

请添加图片描述
算法实现

void bubble_sort(int a[], int n)
{
    for (int i = 0; i < n-1; i++)
    {
        //单趟从左向右,依次比较
        for (int j = 0; j < n - 1 - i; j++)
        {
            if (a[j] > a[j + 1]) std::swap(a[j], a[j + 1]);
        }
    }
}

//优化1:如果某趟没有发生一次交换则证明已经完成排序
void bubble_sort(int a[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        int exchange = 0;
        //单趟从左向右,依次比较
        for (int j = 0; j < n - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                std::swap(a[j], a[j + 1]);
                exchange = 1;
            }
        }
        if (exchange == 0) return;
    }
}
//优化2 -- 双向冒泡
void two_bubble_sort(int a[], int n)
{
	int l = 0, r = n - 1, flag = 1;
	while (l < r)
	{
		for (int i = l; i < r; i++)
		{
			if (a[i] > a[i + 1])
			{
				std::swap(a[i], a[i + 1]);
				flag = i;
			}
		}
		r = flag;
		for (int i = r - 1; i >= l; i--)
		{
			if (a[i] > a[i + 1])
			{
				std::swap(a[i], a[i + 1]);
				flag = i;
			}
		}
		l = flag;
	}
}

算法评价
在这里插入图片描述
冒泡排序算法辅助空间复杂度为O(1),也就是说它是一个就地排序。另外,当i>i日R[i].key=R[i].key时,两者没有逆序,不会发生交换,也就是说使R[i]和R[i]的相对位置保持不变,所以冒泡排序是一种稳定的排序方法。


3.2 快速排序

Hoare版

算法思想

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

请添加图片描述
再上递归展开图:和二叉树的前序遍历差不多
请添加图片描述
算法实现

void quick_sort(int a[], int l, int r)
{
    if (l >= r) return;
    //1. 选key, 假设左边第一个为key
    int keyi = l;
    //2. 找到key的正确位置
    int st = l, ed = r;
    while (st < ed)
    {
        while (ed > st && a[ed] >= a[keyi]) --ed;
        while (ed > st && a[st] <= a[keyi]) ++st;
        std::swap(a[st], a[ed]);
    }
    //3. 将key交换到正确位置
    std::swap(a[st], a[keyi]);;
    keyi = st;
    //4. 继续下分
    quick_sort(a, l, keyi - 1);
    quick_sort(a, keyi + 1, r);
}

在这里插入图片描述
记住上面这三个关键点。
快速排序的时间复杂度是O(nlogn).如下:
在这里插入图片描述

上面是Hoare大佬的原版思路,但有些人认为Hoare的方法有很多小坑,于是又有许多人提出了快速排序的其他实现思路,如挖坑法,前后指针法,下面我们一一道来

挖坑法

算法思想

  1. 先将key保存,将l设置为hole
  2. 然后从右向左找 < key的数, 找到则将其放到hole里,更新hole
  3. 然后从左向右找 > key的数, 找到则将其放到hole里,更新hole
  4. 直到 l >= r, 此时hole为key应放的位置

在这里插入图片描述

算法实现

void quick_sort(int a[], int l, int r)
{
    if (l >= r) return;
    //1. 选key, 假设左边第一个为key
    int key = a[l];
    int hole = l;
    //2. 找到key的正确位置
    int st = l, ed = r;
    while (st < ed)
    {
        while (ed > st && a[ed] >= key) --ed;
        a[hole] = a[ed];
        hole = ed;
        while (ed > st && a[st] <= key) ++st;
        a[hole] = a[st];
        hole = st;
    }
    //3. 将key交换到正确位置
    a[hole] = key;
    //4. 继续下分
    quick_sort(a, l, hole - 1);
    quick_sort(a, hole + 1, r);
}
快速排序前后指针法

算法思想
在这里插入图片描述

算法实现

void quick_sort(int a[], int l, int r)
{
    if (l >= r) return;
    //1. 选key, 假设左边第一个为key
    int cur, prev, keyi;
    prev = keyi = l;
    cur = prev + 1;
    while (cur <= r) 
    {
        if (a[cur] < a[keyi] && ++prev != cur) 
        {
            std::swap(a[prev], a[cur]);
        }
        cur++;
    }
    std::swap(a[keyi], a[prev]);
    keyi = prev;
    quick_sort(a, l, keyi - 1);
    quick_sort(a, keyi + 1, r);
}
快速排序的非递归

用栈来模拟

void quick_sort(int a[], int l, int r)
{
    std::stack<int> st;
    st.push(r);
    st.push(l);
    while (st.size())
    {
        int begin = st.top();
        st.pop();
        int end = st.top();
        st.pop();
        //单次快排过程
        int x = a[begin + end >> 1], i = begin - 1, j = end + 1;
        while (i < j)
        {
            do i++; while (a[i] < x);
            do j--; while (a[j] > x);
            if (i < j) std::swap(a[i], a[j]);
        }
        //插入新的划分段
        if (j + 1 < end)
        {
            st.push(end);
            st.push(j + 1);
        }
        if (begin < j)
        {
            st.push(j);
            st.push(begin);
        }
    }
}

四、归并排序

递归版本

算法思想

基本思想:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

请添加图片描述
形象来讲:就是将数组拆成一个个元素,再逐渐将它们组合起来。这符合递归的特性,下面我们通过递归展开图来看。

请添加图片描述
递归展开图虽然看起来像把数组里的元素拆成了一个个新数组,但我们必须要清晰的认识到这些元素还是在原数组里。明白了这点,让我们来好好思考一下如何归并。有人说:交换一下就行了。比如上面最下面一层10 和 6归并回去的时候,大的和小的交换一下位置,不就有序了。但倒数第二层呢?4个数互相交换吗?这就有点复杂化了。
比较好的做法是创建一个临时数组tmp,将需要归并的元素通过直接插入排序插入到临时数组里面,再把临时数组拷贝回去。如下图

在这里插入图片描述
算法实现

void merge_sort(int a[], int l, int r, int tmp[])
{
    // 1. 终止条件
    if (l >= r)
        return;
    // 2. 不断递归划分
    int mid = l + r >> 1;
    merge_sort(a, l, mid, tmp);
    merge_sort(a, mid + 1, r, tmp);
    // 3. 开始归并, 左区间[l, mid] 右区间[mid+1, r] 起始位置 end = l
    int l1 = l, r1 = mid;
    int l2 = mid + 1, r2 = r;
    int end = l;
    while (l1 <= r1 && l2 <= r2)
    {
        if (a[l1] <= a[l2]) tmp[end++] = a[l1++];
        else tmp[end++] = a[l2++];
    }
    // 3.1 左区间可能有剩余
    while (l1 <= r1) tmp[end++] = a[l1++];
    // 3.2 右区间可能有剩余
    while (l2 <= r2) tmp[end++] = a[l2++];
    // 3.2 将排序好的数组拷贝到原数组内
    memcpy(a + l, tmp + l, sizeof(int) * (r - l + 1));
}

非递归版本

归并过程由一一归并到二二归并,再到四四归并…直到gap > n

在这里插入图片描述
在这里插入图片描述

void merge_sort(int* a, int l, int r)
{
    int n = r - l + 1;
    int* tmp = new int[n];
    int gap = 1;//左右区间的大小
    while (gap < n)
    {
        for (int i = 0; i < n; i += 2 * gap)
        {
            // 开始归并, 左区间[i, i+gap-1] 右区间[i+gap, i+gap + gap-1] 起始位置 end = i
            int l1 = i, r1 = i + gap-1;
            int l2 = i + gap, r2 = i + 2 * gap - 1;
            int end = i;
            //情况1:r1 越界 表明l2,r2都越界了,直接break
            //情况2:l2 越界 同上,直接break
            //情况3: r2 越界 更改r2 = n-1
            //情况4:无越界 
            if (l2 >= n) break;
            if (r2 >= n) r2 = n - 1;
            while(l1 <= r1 && l2 <= r2)
            {
                if (a[l1] <= a[l2]) tmp[end++] = a[l1++];
                else tmp[end++] = a[l2++];
            }
            // 左区间可能有剩余
            while (l1 <= r1) tmp[end++] = a[l1++];
            // 右区间可能有剩余
            while (l2 <= r2) tmp[end++] = a[l2++];
            //这里用end - i,不要用2*gap, 因为存在越界的情况,拷贝的大小 <= gap*2
            memcpy(a + i, tmp + i, sizeof(int) * (end-i));
        }
        gap *= 2;
    }
    delete[] tmp;
}

五、基数排序

算法思想

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog®m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

二种方式:

最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。

最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。

算法实现 – LSD

void radix_sort(int a[], int n)
{
    //确定基数 -- 按个 十...排序,因此基数 0-9 共10个
    const int radix = 10;
    std::queue<int> q[radix];
    int mol = 10;
    while (1)
    {
        //1. 分配
        for (int i = 0; i < n; i++)
        {
            //1. 求key
            // 10013 取十位 模100,再除10
            int k = a[i] % mol;
            k /= (mol / 10);
            //2. 入队
            q[k].push(a[i]);
        }
        // 如果都分配到q[0]则表示关键字序号已经超过k1
        if (q[0].size() == n) break;
        //2. 回收
        int end = 0;
        for (int i = 0; i < radix; i++)
        {
            while (q[i].size())
            {
                int t = q[i].front();
                q[i].pop();
                a[end++] = t;
            }
        }
        //3. 开始排序kd-1位
        mol *= 10;
    }
}

六、计数排序

算法思想

计数排序是一种非比较排序,其核心是将序列中的元素作为键存储在额外的数组空间中,而该元素的个数作为值存储在数组空间中,通过遍历该数组排序。

在这里插入图片描述
算法实现

void count_sort(int a[], int n)
{
    int Max = a[0];
    for (int i = 1; i < n; i++)
    {
        Max = std::max(Max, a[i]);
    }
    int* count = new int[Max]{0};
    for (int i = 0; i < n; i++)
    {
        count[a[i]]++;
    }
    int end = 0;
    for (int i = 0; i < Max; i++)
    {
        while (count[i])
        {
            a[end++] = i;
            count[i]--;
        }
    }
}

算法评价

时间复杂度:O (N+Max)

空间复杂度:O (Max)

内排序总结

排序方法时间复杂度空间复杂度稳定性
平均情况最坏情况最好情况
直接插入排序O( n 2 n^2 n2)O( n 2 n^2 n2)O( n n n)O(1)稳定
折半插入排序O( n 2 n^2 n2)O( n 2 n^2 n2)O( n n n)O(1)稳定
希尔排序O( n 1.3 n^{1.3} n1.3)O(1)不稳定
简单选择排序O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)不稳定
堆排序O( n l o g 2 n nlog_2{n} nlog2​n)O( n l o g 2 n nlog_2{n} nlog2​n)O( n l o g 2 n nlog_2{n} nlog2​n)O(1)不稳定
冒泡排序O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)稳定
快速排序O( n l o g 2 n nlog_2{n} nlog2​n)O( n 2 n^2 n2)O( n l o g 2 n nlog_2{n} nlog2​n)O( l o g 2 n log_2{n} log2​n)不稳定
归并排序O( n l o g 2 n nlog_2{n} nlog2​n)O( n l o g 2 n nlog_2{n} nlog2​n)O( n l o g 2 n nlog_2{n} nlog2​n)O( n n n)稳定
基数排序O( d ( n + r ) d(n+r) d(n+r))O( d ( n + r ) d(n+r) d(n+r))O( d ( n + r ) d(n+r) d(n+r))O( r r r)稳定
计数排序O( n n n)O( n n n)O( n n n)O( r a n g e range range)不稳定
八大排序算法——(万字图文详解) 本篇博客将对“直接插入排序”、“希尔排序”、“直接选择排序”、“堆排序”、“冒泡排序”、“快速排序”、“归并排序”、“计数排序”进行详细的解析(算法逻辑、具体实现过程、时间复杂度、稳定性),并附以图片帮助大家更好地理解算法逻辑以及实现每个排序的参考代码。 阅读详情

相关推荐

【C++】排序算法

冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序、快速排序、计数排序、基数排序、桶排序、外排序

phoenixFlyzzz的博客 2063

六种常见的排序算法

常见的六种排序算法

qq_46721967的博客 7793

排序算法:稳定的排序算法

元素,并围绕主元对列表进行分区,将较小的元素放入低数组中,将所有较大的元素放入高数组中。然后,我们对他们的第十位的值进行排序。因此,我们可以对任意大小的列表进行排序,而无需在冒泡排序中使用任何额外的空间。我们可以说,子问题可以被视为对数组的一部分进行排序,从任何索引 s(start) 开始,到任何索引 e(end) 结束。正如我们上面所讨论的,最大堆是一个完全二叉树,其中每个内部节点中的值都大于或等于该节点的子节点中的值。此外,每次迭代后,已排序子数组的大小都会增加,而未排序子数组的大小会减少。

新华编程特战队 1858

常用十大排序算法

列举了常见的十大内部排序算法:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序,计数排序,桶排序。

qq_51664685的博客 15万+

八种排序算法

偶尔有看到排序算法,想起来大学里老师也有讲授过冒泡排序、快速排序等,不过现在已经没什么概念,一查发现排序算法有八种,有的甚至连名字都没听过,感概平时看的少。既然已经看到了,就干脆了解下基础概念,避免在后续学习途中,出现一看就懵逼的情况。   冒泡排序 冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到...

dobat的博客 3348

排序算法总结及C++实现

文章目录1 引入 认识时间复杂度2 补充 对数器3 排序算法分析3.1 基于比较的排序3.1.1 冒泡排序3.1.2 选择排序3.1.3 插入排序3.1.4 归并排序补充题目 小和问题补充题目 逆序数3.1.5 快速排序3.1.6 堆排序3.2 非基于比较的排序3.2.1 计数排序3.2.2 桶排序3.2.3 基数排序4 排序总结4.1 稳定性4.2 工程中的综合排序算法4.3 有关排序...

李滚滚的博客 2222

十大常用经典排序算法总结!!!

爆肝整理!堪称全网最详细的十大常用经典排序算法总结!!! 写在开头,本文经过参考多方资料整理而成,全部参考目录会附在文章末尾。很多略有争议性的细节都是在不断查阅相关资料后总结的,具有一定普适性。 总表: 相关解释: 稳定:如果原本序列中a在b前面且a=b,排序后a仍在b前面,顺序不变; 不稳定:如果原本序列中a在b前面且a=b,排序后a可能在b后面,顺序可能发生改变; 内排序:所有排序操作均在内存中完成; 外排序:由于数据量太大,将其放入磁盘中,排序过程中需要磁盘与内存之间的数据传输;

Jing Sir的博客 5万+

AutoCAD Plant 3D自定义零件库实战:手把手教你用Python创建参数化槽式三通

本文详细介绍了如何利用Python脚本在AutoCAD Plant 3D中创建参数化槽式三通组件,从API原理到实战开发,帮助用户构建高效的自定义零件库。通过Python装饰器系统控制零件属性和行为,实现几何建模、参数管理和规格编辑器集成,提升工业管道设计的标准化和效率。

weixin_28267011的博客 331

九大排序算法再总结

如果要转载,需要注明出处: http://blog.youkuaiyun.com/xiazdong 本文是 http://blog.youkuaiyun.com/xiazdong/article/details/7304239 的补充,当年看了《大话数据结构》总结的,但是现在看了《算法导论》,发现以前对排序的理解还不深入,所以打算对各个排序的思想再整理一遍。 本文首先介绍了基于比较模型的排序算法,

xiazdong 31万+

win11下的MySQL安装

目前官方最新版本是8.0.26,考虑到其稳定性、可靠性还需一定周期保证,所以使用官方版求稳定仍然建议5.7系列。3、选择MySQL Servers 5.7.38 -x64,然后按绿色箭头将选中的版本移植到右边选中框中。4、点击下方蓝色Advanced Options,选择安装位置。1、在开始界面搜索MySQL,点击command line。4、在“系统变量”中选择“path”,点击编辑。5、新建——>增加MySQL路径——>确定,12、execute,安装好后next。9、不需要做修改,直接点击next。.

rensweet的博客 2万+

告别CPU空转!用STC8的SPI+DMA高效驱动上百颗WS2812B灯珠

本文详细解析了如何利用STC8单片机的SPI+DMA外设高效驱动WS2812B全彩灯珠,解决传统软件延时驱动方式在长灯带应用中的性能瓶颈。通过硬件方案设计、数据格式转换和DMA传输配置,实现高达400Hz的刷新率和低于5%的CPU占用率,适用于大规模灯光项目。

weixin_30847939的博客 395

【排序算法】排序算法总结

排序算法总结,将排序算法的分类、稳定性和特点进行一个总结,并附有跳转到对应详解的链接,方便大家学习

weixin_52811588的博客 983

esxi8.0.3如何添加USB外置硬盘

本文介绍了在ESXi系统中配置外置USB硬盘作为数据存储的完整步骤:1)通过SSH禁用USB仲裁服务并关闭自启;2)识别已连接的USB硬盘设备路径;3)使用partedUtil创建GPT分区表并计算扇区范围;4)设置VMFS6分区并格式化。关键命令包括停止usbarbitrator服务、partedUtil分区操作以及vmkfstools格式化命令。整个过程需通过SSH执行,最终将USB硬盘配置为名为"USB_Datastore"的VMFS6存储设备。

qq_41683719的博客 1545

稳定排序算法有哪些

稳定排序算法有哪些 相信您已经掌握了很多种排序算法,比如冒泡排序、插入排序、希尔排序、选择排序等。这些排序算法中,有些是 “稳定” 的,有些是 “不稳定” 的。 给定的待排序序列中,经常会包含相同的元素,例如: 3 1 2 4 2 此序列中包含两个元素 2,为了区分它们,我们分别称它们为 “红 2” 和 “绿 2”。 评价一个排序算法是否稳定,是指该算法完成排序的同时,是否会改变序列中相同元素的相对位置。例如,上面序列中红 2 和绿 2 的相对位置是:红 2 位于绿 2 的左侧,或者说绿 2 位于红 2

ccc369639963的博客 1万+

ZYNQ 7020 之 FPGA知识点重塑笔记一——串口通信

通信方式一般分为串行通信和并行通信。并行通信是指多比特数据同时通过并行线进行传送。这种传输方式通信线多、成本高,故不宜进行远距离通信,通常传输距离小于 30 米。串行通信是指数据在一条数据线上,一比特接一比特地按顺序传送的方式。这种运输方式通常节省传输线,大大降低使用成本,但数据传送速度慢。综上可知,串行通信主要应用于长距离、低速率的通信场合。本次实验我们主要讲解下串行通信。串行通信一般有2种通信方式:同步串行通信和异步串行通信。同步串行通信。

m0_51430584的博客 3094

零基础快速学习 ABAP 读者意见反馈和下一步写作计划表

大家在学习教程过程中,如果有任何关于 SAP ABAP 开发方面想了解的内容,可以直接在教程各篇文章下评论留言,我会将大家的意见统一汇总到下面的表格,作为我更新教程的内容参考来源之一。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 4273

排序算法总结

排序算法总结 概述: 转眼大三了,总结下排序算法,对以后推免,找工作都十分有益。 先来个排序算法总结,再详细讨论。 一、冒泡排序(Bubble Sort) 第一个就总结学生平时最常用的冒泡排序吧。 1. 基本思想 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越...

qq_40691562的博客 2381

98DX3236内核编译过程小结

0.条件(1)Marvell技术支持提供的压缩文件:GNU EABI:arm-mv5sft-linux-gnueabi_SW3.2.tar.bz2.tar.bz2armebv7-marvell-linux-gnueabi-softfp_i686_201201.tar.bz2CPSS代码:Cpss-PP-DxCh-4.2_012.zipLinux内核文件:lsp-4.2_012.zipLSP-Uni...

snaking616 1802

什么是排序算法?常见的排序算法有哪些?

计数排序适用于数据范围较小且已知的情况,其时间复杂度为线性时间,非常适合处理小范围内的数据排序。基数排序适用于整数排序,特别是当数据范围较大但数据量适中时。它通过多次应用计数排序来实现多轮排序,从而克服了传统排序算法在处理大范围数据时的效率问题。

破损的天堂鸟博客 1226

Linux | Ubuntu18.04安装WIFI6 AX201驱动完整教程

本节介绍了如何在Ubuntu18下安装AX201驱动的教程。

九七的博客 8881

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

各种排序算法总结

排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大,所以排序算法对算法本身的速度要求很高。而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。在后面我将给出详细的说明。  对于排序的算法我想先做一点简单的介绍,也是给这篇文章理一个提纲。 我将按照算法的复杂度,从简单到难来分析算法。  第一部分是简单排序算法,后面你将看到他们的共同点是算法复杂度为O(N*N)

eecrazy的专栏 696

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

排序算法-10种排序算法

文章目录一、排序算法是什么?1.解释2.内部排序3.外部排序二、排序算法介绍及实现1.冒泡排序算法描述四、测试 一、排序算法是什么? 1.解释 这里引入百度百科的解释: 谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。 在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。 2.内

GGB__的博客 932

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【排序算法】八大经典排序算法详解

理解这些基础排序算法不仅是掌握数据结构的关键,更是优化实际工程问题的基础。建议读者通过可视化工具(如Visualgo)观察算法的执行过程,并尝试自己实现不同版本的排序算法来加深理解。

qq_40205510的博客 3110

十大排序算法

算法稳定性:单次比较后,两个值相等的邻近元素的位置在排序后,相对位置没有改变。

一名想做出点成就的后端~ 1428

算法设计与分析——排序算法:十大排序算法总结

排序算法我们已经通过前序文章全部详细说明了,值的一提的是,我们说述的排序算法都指代的是内部排序算法。而实际上,排序算法可以分为内部排序和外部排序。内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等,这些算法我们在前序文章都意义详细的阐述了,现用一张图概括前序文章的十大排序算法: ...

冯·诺依曼 1万+
上一篇: 【问题】栈区地址分配之谜:为什么局部变量的地址会递增?
下一篇: 【C++】类型转换
ProcedureStone
博客等级 码龄4年 254粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值