归并排序(merge Sort)

归并排序采用自底向上的方法,通过逐步合并小的有序子文件形成大的有序文件,直至最后得到一个长度为n的有序序列。归并过程对应于二叉树的构建,时间复杂度为O(nlog2n),空间复杂度为O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序有两种方式:

(1): 自底向上的方法
自底向上的基本思想是:第1趟归并排序时,将待排序的文件R[1..n]看作是n个长度为1的有序子文件,将这些子文件两两归并,若n为偶数,则得到n/2个长度为2的有序子文件;若n为奇数,则最后一个子文件轮空(不参与归并)。故本趟归并完成后,前n/2 - 1个有序子文件长度为2,但最后一个子文件长度仍为1;第2趟归并则是将第1趟归并所得到的n/2个有序的子文件两两归并,如此反复,直到最后得到一个长度为n的有序文件为止。

初始化:{43,23,54,44,2,7,19}
第一趟:{23,43,44,54,2,7,19}
第二趟:{23,43,44,54,2,7,19}
第三趟:{2,7,19,23,43,44,54}
      第一趟   【43,23】【54,44】【2,7】【19】
      第二趟   【23,43,44,54】【2,7,19】 
      第三趟   【2,7,19,23,43,44,54】 
   // 归并排序
        public void Merge(List<int> seqlist,int len)
        {
            int m = 0; //临时顺序表的起始位置
            int l1 = 0;//第1个有序表的起始位置
            int h1;    //第1个有序表的结束位置
            int l2;    //第2个有序表的起始位置
            int h2;    //第2个有序表的结束位置
            int i = 0; //临时表示第一个有序表的起始位置
            int j = 0; //临时表示第二个有序表的起始位置
            // 临时表,用于临时将2个有序表合并为一个有序表
            List<int> tmp = new List<int>();
            for (int q = 0; q < seqlist.Count; q++)
            {
                tmp.Add(0);// 给list添加值
            }
            // 归并处理
            while (l1+len<seqlist.Count)
            {
                l2 = l1 + len;//第二个有序表的开始位置
                h1 = l2 - 1;  //第一个有序表的结束位置
                // 第二个有序表的结束位置
                h2 = (l2 + len - 1 < seqlist.Count) ? l2 + len - 1 : seqlist.Count - 1;
                j = l2; //第二个有序表的起始位置赋给j
                i = l1; //第一个有序表的起始位置赋给i
                // 两个有序表中的记录没有排序完
                while ((i<=h1)&&(j<=h2))
                {
                    //第一个有序表记录的关键码小于第二个有序表记录的关键码
                    if (seqlist[i]<=seqlist[j])
                    {
                        tmp[m++] = seqlist[i++];
                    }
                    else
                    {
                        tmp[m++] = seqlist[j++];

                    }
                }
                // 第一个有序表中还有记录没有排序完
                while (i<=h1)
                {
                    tmp[m++] = seqlist[i++];
                }
                // 第二个有序表中还有记录没有排序完
                while (j<=h2)
                {
                    tmp[m++] = seqlist[j++];
                }
                l1 = h2 + 1;
            }
            i = l1;
            // 原顺序表中还有记录没有排序完
            while (i<seqlist.Count)
            {
                tmp[m++] = seqlist[i++];
            }
            // 临时顺序表中的记录复制到顺序表,使原顺序表中的记录有序
            for (i = 0; i < seqlist.Count; i++)
            {
                seqlist[i] = tmp[i];
            }
        }
    // 二路归并排序算法
    public void MergeSort(List<int> seqlist)
      {
          int n = 1;// 归并增量
          while (n < seqlist.Count)
          {
              Merge(seqlist,n);
              n *= 2;
          }
      }

对于n个记录的顺序表,将这n个记录看作叶子结点,若将两两归并生成的子
表看作它们的父结点,则归并过程对应于由叶子结点向根结点生成一棵二叉树的
过程。所以,归并趟数约等于二叉树的高度减1,即log2n,每趟归并排序记录关
键码比较的次数都约为n/2,记录移动的次数为2n(临时顺序表的记录复制到原
顺序表中记录的移动次数为n)。因此,二路归并排序的时间复杂度为O(nlog2n)。
而二路归并排序使用了n个临时内存单元存放记录,所以,二路归并排序算法的
空间复杂度为O(n)。

### 归并排序的实现原理 归并排序是一种基于分治法(Divide and Conquer)的有效排序算法。其核心思想是通过将待排序数组分割为更小的部分,分别对这些部分进行排序后再将其合并成为一个整体有序的结果[^1]。 具体来说,归并排序的过程可以分为以下几个方面: #### 1. **分解** 整个数据集被递归地划分为较小的子集合,直到每个子集合仅包含单个元素为止。因为单一元素本身已经是有序的,所以这一步骤完成了基础单元的创建[^2]。 #### 2. **合并** 当所有的子集合都已经被拆解到最小单位之后,开始逐步地把它们两两合并起来,在每次合并的过程中都会确保新形成的组合也是按照顺序排列好的。这种“归并”的过程会一直持续下去,直至最终形成一个完整的、完全有序的数据列表[^3]。 以下是归并排序的核心伪代码表示: ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left_half = merge_sort(arr[:mid]) right_half = merge_sort(arr[mid:]) return merge(left_half, right_half) def merge(left, right): sorted_array = [] i = j = 0 while i < len(left) and j < len(right): if left[i] < right[j]: sorted_array.append(left[i]) i += 1 else: sorted_array.append(right[j]) j += 1 sorted_array.extend(left[i:]) sorted_array.extend(right[j:]) return sorted_array ``` 这段代码展示了如何使用 Python 来实现归并排序的功能。其中 `merge` 函数负责执行实际的合并操作,而 `merge_sort` 则控制着递归调用以及何时停止进一步划分输入数组。 ### 时间复杂度分析 由于每一次都将当前序列分成两半处理,并且每一层都需要遍历全部 n 项来进行比较和移动,因此总的运行时间为 O(n log n)。 ### 稳定性特点 值得注意的是,归并排序属于稳定性的排序方式之一,这意味着即使存在相等的关键字记录也不会改变彼此原有的次序关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值