当前位置: 首页 > ai >正文

【算法分析与设计】研究生第二次算法作业:基于分治策略的有序数组中位数查找与逆序对计数 latex源码和pdf

pdf:【免费】【算法分析与设计】基于分治策略的有序数组中位数查找与逆序对计数:高效算法设计及复杂度分析文档的主要内容资源-CSDN下载

\documentclass[12pt,a4paper]{article}
\usepackage{geometry}
\geometry{left=2.5cm,right=2.5cm,top=2.0cm,bottom=2.5cm}
\usepackage[english]{babel}
\usepackage{amsmath,amsthm}
\usepackage{amsfonts}
\usepackage{algorithmicx}\usepackage{algpseudocode}
\usepackage{fancyhdr}
\usepackage{ctex}
\usepackage{array}
\usepackage{listings}
\usepackage{color}
\usepackage{graphicx}
\usepackage{algorithm} 
\usepackage{algpseudocode}

\begin{document}


\title{\heiti《算法分析与设计》第二次作业}  % ctex已集成黑体

\date{} 

\maketitle

\section*{题目1:寻找两个有序数组的中位数}
设数组 $X[0..n-1]$ 和 $Y[0..n-1]$ 均为升序排列,各包含$n$个元素。要求设计时间复杂度为$O(\log n)$的分治算法,找出合并后$2n$个元素的中位数(当元素个数为偶数时取中间两个数的平均值),并证明算法的时间复杂度。

\subsection*{算法设计与分析}
\paragraph{问题转化} 合并后数组长度为$2n$,中位数等价于:
$$
\text{Median} = \frac{\text{第}n\text{小元素} + \text{第}(n+1)\text{小元素}}{2}
$$

\paragraph{分治策略} 通过递归排除无关元素实现对数时间复杂度:
\begin{enumerate}
    \item \textbf{递归基准}:
    \begin{itemize}
        \item 若某数组为空,直接取另一数组第$k$元素
        \item 当$k=1$时,返回两数组首元素较小值
    \end{itemize}
    
    \item \textbf{元素比较}:
    \begin{itemize}
        \item 取两数组前$\lfloor k/2 \rfloor$个元素(不超过数组长度)
        \item 比较临界值$X[i-1]$与$Y[j-1]$
    \end{itemize}
    
    \item \textbf{范围排除}:
    \begin{itemize}
        \item 当$X[i-1] < Y[j-1]$时,排除$X$前$i$个元素
        \item 否则排除$Y$前$j$个元素
    \end{itemize}
\end{enumerate}

\subsection*{算法伪代码}
\begin{algorithm}[H]
\caption{寻找第k小元素}
\begin{algorithmic}[1]
\Function{FindKth}{$X$, $x\_len$, $Y$, $y\_len$, $k$}
    \If{$x\_len = 0$}
        \State \Return $Y[k-1]$
    \EndIf
    \If{$y\_len = 0$}
        \State \Return $X[k-1]$
    \EndIf
    \If{$k = 1$}
        \State \Return $\min(X[0], Y[0])$
    \EndIf
    
    \State $i \gets \min(\lfloor k/2 \rfloor, x\_len)$
    \State $j \gets \min(\lfloor k/2 \rfloor, y\_len)$
    
    \If{$X[i-1] < Y[j-1]$}
        \State \Return \Call{FindKth}{$X+i$, $x\_len-i$, $Y$, $y\_len$, $k-i$}
    \Else
        \State \Return \Call{FindKth}{$X$, $x\_len$, $Y+j$, $y\_len-j$, $k-j$}
    \EndIf
\EndFunction
\end{algorithmic}
\end{algorithm}
\subsection*{时间复杂度证明}
递归过程满足递推关系:
\[
T(k) = T\left(\frac{k}{2}\right) + O(1)
\]
由主定理可得时间复杂度为$O(\log k)$。对于中位数问题需执行两次$k=n$的查找,故总时间复杂度为:
\[
2 \times O(\log n) = O(\log n)
\]

\subsection*{代码实现}
\begin{enumerate}
    \item C++实现
    \begin{lstlisting}[language=C++, basicstyle=\small\ttfamily]
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int find_kth(int X[], int x_len, int Y[], int y_len, int k) {
    if (x_len == 0) return Y[k-1];
    if (y_len == 0) return X[k-1];
    if (k == 1) return min(X[0], Y[0]);
    
    int i = min(k/2, x_len), j = min(k/2, y_len);
    return (X[i-1] < Y[j-1]) ?
        find_kth(X+i, x_len-i, Y, y_len, k-i) :
        find_kth(X, x_len, Y+j, y_len-j, k-j);
}

double findMedian(int X[], int Y[], int n) {
    return (find_kth(X,n,Y,n,n) + find_kth(X,n,Y,n,n+1)) / 2.0;
}
    \end{lstlisting}

    \item Python实现
    \begin{lstlisting}[language=Python, basicstyle=\small\ttfamily]
def find_kth(X, x_start, x_len, Y, y_start, y_len, k):
    if x_len == 0: return Y[y_start + k-1]
    if y_len == 0: return X[x_start + k-1]
    if k == 1: return min(X[x_start], Y[y_start])
    
    i = min(k//2, x_len)
    j = min(k//2, y_len)
    
    if X[x_start+i-1] < Y[y_start+j-1]:
        return find_kth(X, x_start+i, x_len-i, Y, y_start, y_len, k-i)
    else:
        return find_kth(X, x_start, x_len, Y, y_start+j, y_len-j, k-j)

def find_median(X, Y):
    n = len(X)
    m1 = find_kth(X,0,n, Y,0,n, n)
    m2 = find_kth(X,0,n, Y,0,n, n+1)
    return (m1 + m2) / 2
    \end{lstlisting}
\end{enumerate}
\section*{题目2:基于分治策略的逆序对计数算法及复杂度分析}
给定实数序列$A=\{a_1,a_2,...,a_N\}$,若存在下标$i<j$且$a_i>a_j$,则称有序对$(a_i, a_j)$为一个逆序对。本文提出基于分治算法的高效解决方案,并给出严格的时间复杂度证明。

\subsection*{算法设计与分析}
\subsubsection*{问题分析}
逆序对在序列中体现为满足$i<j$且$a_i>a_j$的有序对$(a_i,a_j)$。采用分治法的核心思想是将原问题分解为三个子问题:
\begin{itemize}
    \item 左半部分$A_L$内部的逆序对数目
    \item 右半部分$A_R$内部的逆序对数目
    \item 跨越$A_L$和$A_R$的逆序对数目
\end{itemize}

\subsubsection*{分治策略}
\begin{enumerate}
    \item \textbf{分解(Divide)}:将当前序列$A[p..r]$均分为两个子序列
    $$
    A_L = A[p..\lfloor (p+r)/2 \rfloor], \quad 
    A_R = A[\lfloor (p+r)/2 \rfloor+1..r]
    $$
    
    \item \textbf{解决(Conquer)}:递归求解子问题
    $$
    Inv_L = \text{Count}(A_L), \quad 
    Inv_R = \text{Count}(A_R)
    $$
    
    \item \textbf{合并(Combine)}:在归并有序子序列时统计跨子序列逆序对
\end{enumerate}

\subsubsection*{关键步骤}
归并过程中的逆序对计数策略:
\begin{itemize}
    \item 当右子数组元素$a_j$被选入合并数组时
    \item 左子数组剩余元素数量$count = |A_L| - i$ 
    \item 此时$a_j$贡献的逆序对数为$count$
    \item 即:$\forall k \in [i, |A_L|), a_k > a_j$
\end{itemize}

\subsubsection*{形式化伪代码描述}
\begin{algorithm}[H]
\caption{逆序对计数算法}
\begin{algorithmic}[1]
\Function{CountInversions}{$A[0..n-1]$}
    \If{$n \leq 1$}
        \State \Return $(0, A)$
    \EndIf
    \State $mid \gets \lfloor n/2 \rfloor$
    \State $(left\_inv, L) \gets \text{CountInversions}(A[0..mid-1])$
    \State $(right\_inv, R) \gets \text{CountInversions}(A[mid..n-1])$
    \State $(cross\_inv, A') \gets \text{MergeCount}(L, R)$
    \State \Return $(left\_inv + right\_inv + cross\_inv, A')$
\EndFunction

\Function{MergeCount}{$L[0..p-1], R[0..q-1]$}
    \State $i \gets 0, j \gets 0, k \gets 0, inv \gets 0$
    \State Initialize $merged[0..p+q-1]$
    \While{$i < p$ \textbf{and} $j < q$}
        \If{$L[i] \leq R[j]$}
            \State $merged[k++] \gets L[i++]$
        \Else
            \State $merged[k++] \gets R[j++]$
            \State $inv \gets inv + (p - i)$  
        \EndIf
    \EndWhile
    \State Copy remaining elements
    \State \Return $(inv, merged)$
\EndFunction
\end{algorithmic}
\end{algorithm}

\subsection*{时间复杂度分析}
设$T(n)$表示处理长度为$n$的数组所需时间,可得递推关系:
$$
T(n) = 2T\left(\frac{n}{2}\right) + \Theta(n)
$$
根据主定理(Master Theorem):
\begin{itemize}
    \item $a = 2$, $b = 2$, $f(n) = \Theta(n)$
    \item 满足情况2:$f(n) = \Theta(n^{\log_b a})$
    \item 得时间复杂度为$\Theta(n \log n)$
\end{itemize}

\subsection*{代码实现}
\begin{enumerate}
    \item \textbf{C++实现}
    \begin{lstlisting}[language=C++, basicstyle=\scriptsize\ttfamily]
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

using namespace std;

int mergeAndCount(vector<int>& arr, const vector<int>& left, const vector<int>& right) {
    int i = 0, j = 0, k = 0, inv_count = 0;
    while (i < left.size() && j < right.size()) {
        if (left[i] <= right[j]) {
            arr[k++] = left[i++];
        } else {
            arr[k++] = right[j++];
            inv_count += (left.size() - i);
        }
    }
    while (i < left.size()) arr[k++] = left[i++];
    while (j < right.size()) arr[k++] = right[j++];
    return inv_count;
}

int countInversions(vector<int>& arr) {
    if (arr.size() <= 1) return 0;
    int mid = arr.size() / 2;
    vector<int> left(arr.begin(), arr.begin() + mid);
    vector<int> right(arr.begin() + mid, arr.end());
    int inv = countInversions(left) + countInversions(right);
    vector<int> merged(arr.size());
    inv += mergeAndCount(merged, left, right);
    arr = merged;
    return inv;
}

int main() {
    int n;
    cout << "请输入n的值:";
    cin >> n;
    vector<int> arr;
    if (n == -1) {
        srand(time(0));
        int length = rand() % 6 + 5;
        arr.resize(length);
        for (int& num : arr) num = rand() % 100 + 1;
        cout << "随机生成的数组:";
        for (int num : arr) cout << num << " ";
        cout << endl;
    } else {
        arr.resize(n);
        cout << "请输入数组元素(空格分隔):";
        for (int i = 0; i < n; ++i) cin >> arr[i];
    }
    vector<int> temp = arr;
    cout << "逆序对数目:" << countInversions(temp) << endl;
    return 0;
}
    \end{lstlisting}
    
    \item \textbf{Python实现}
    \begin{lstlisting}[language=Python, basicstyle=\scriptsize\ttfamily]
from typing import Tuple, List

def count_inversions(arr):
    if len(arr) <= 1:
        return 0, arr
    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]
    left_inv, left_sorted = count_inversions(left)
    right_inv, right_sorted = count_inversions(right)
    merge_inv, merged = merge(left_sorted, right_sorted)
    total = left_inv + right_inv + merge_inv
    return total, merged

def merge(left, right):
    merged = []
    i = j = inv_count = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            inv_count += len(left) - i
            j += 1
    merged += left[i:]
    merged += right[j:]
    return inv_count, merged

n = int(input("请输入n的值:"))
if n == -1:
    import random
    length = random.randint(5, 10)
    arr = [random.randint(1, 100) for _ in range(length)]
    print("随机生成的数组:", arr)
else:
    arr = list(map(int, input("请输入数组元素,空格分隔:").split()))
    if len(arr) != n:
        print("输入长度不匹配!")
        exit()
total, _ = count_inversions(arr)
print("逆序对数目:", total)
    \end{lstlisting}
\end{enumerate}
\end{document}
 

http://www.xdnf.cn/news/15227.html

相关文章:

  • 五、深度学习——CNN
  • 卫星通信终端天线的5种对星模式之二:DVB跟踪
  • FastAdmin项目开发三
  • Anthropic:从OpenAI分支到AI领域的领军者
  • ubuntu18.04 升级Ubuntu 20.04
  • Transformer基础
  • L1正则化 VS L2正则化
  • c++中的STL
  • Redis 实现分布式锁
  • Kotlin文件操作
  • 2025 年 4-6 月大模型备案情况分析
  • 单链表的题目,咕咕咕
  • 【Scratch】从入门到放弃(四):指令大全-九大类之事件、控制、侦测
  • 【小情绪小感悟】
  • houdini 用 vellum 制作一个最简单的布料
  • SiC 型储能充电器设计与研究
  • 岛屿数量问题
  • HT8313功放入门
  • Cell2location maps fine-grained cell types in spatial transcriptomics 文章解析
  • Golang操作MySQL json字段优雅写法
  • 【数据结构初阶】--顺序表(三)
  • 【机器学习实战笔记 16】集成学习:LightGBM算法
  • 【读书笔记】从AI到Transformer:LLM技术演进全解析
  • 智能Agent场景实战指南 Day 11:财务分析Agent系统开发
  • 动态规划基本操作
  • Vue3 学习教程,从入门到精通,Vue3指令知识点及使用方法详细介绍(6)
  • 【TOOL】ubuntu升级cmake版本
  • Linux驱动08 --- 数据库
  • 【PTA数据结构 | C语言版】后缀表达式求值
  • Mamba架构的模型 (内容由deepseek辅助汇总)