【转载】各种数组排序方法总结

本文详细介绍了多种排序算法,包括交换排序、冒泡排序、双向冒泡排序、快速排序、插入排序和选择排序,并通过随机数据初始化数组进行排序演示。此外,文章还实现了快速排序的递归版本和插入排序、选择排序的优化版本,展示了不同排序算法的性能差异。

import java.lang.Math;
import java.util.Random;

/**
 * 排序
 *
 * @author javajack  
 */
public class OrderTest {

    public static void main(String args[]) {
        OrderTest.ExecOrder(2);
    }

    /**
     * 交换值,交换数组的两个值
     * @param array
     * @param i
     * @param j
     */
    private static void swap(int[] array,int i, int j)
    {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }    
    
    /**
     *
     * @param method
     *            1为升序,2为降序
     */
    public static void ExecOrder(int method) {
        int[] array = null;
        array = initArray(10, 210, 10);
        
         //int[] orderarray = bubbleOrder(array,method);
        int[] orderarray = doubleBubbleOrder(array,method);
        //int[] orderarray = insertOrder(array, method);
        //int [] orderarray = quickOrder(array,method);
        //int[] orderarray = selectOrder(array, method);
        for (int i = 0; i < orderarray.length; i++) {
            System.out.println(orderarray[i]);
        }
    }

    /**
     * 取随机数据,初始化一个数组
     *
     * @param min
     *            随机数的最小值
     * @param max
     *            最大值
     * @param size
     *            取得随机数的数量
     * @return
     */
    public static int[] initArray(int min, int max, int size) {
        int[] init = new int[size];

        for (int i = 0; i < size; i++) {
            Random ra = new Random();
            init[i] = min + (int) (Math.random() * (max - min + 1));
            System.out.println(i + "-------" + init[i]);
        }
        return init;
    }

    /**
     * 交换排序方法
     * 原理:依次交换值
     * @param array
     * @return
     */
    public static int[] convertOrder(int[] array, int method) {
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++)
            {
                if (method==2)
                {
                    if (array[i] < array[j])
                        swap(array,i,j);
                }else if (method == 1) {
                    if (array[i] > array[j])
                        swap(array,i,j);
                }
            }
        }
        return array;
    }

    /**冒泡排序方法
     * 原理:从最后一个开始将小的或大的逐渐冒出
     * @param array
     * @param method
     * @return
     */
    public static int[] bubbleOrder(int[] array,int method)
    {
        for(int i=0;i<array.length;i++)
        {
            for (int j=array.length -1 ;j>i;j--)
            {
                if (method==2)
                {
                    if (array[i] < array[j])
                        swap(array,i,j);
                }else if (method==1)
                    if (array[i] > array[j])
                        swap(array,i,j);
            }
        }
        return array;
    }
    
    /**
     * 双向冒泡排序
     * 原理:类似于冒泡排序,只不过是双向的
     * @param array
     * @param method
     * @return
     */
    public static int[] doubleBubbleOrder(int[] array,int method)
    {
        int left = 0;
        int right = array.length -1 ;
        while (left < right)
        {
            for(int i=left;i<=right;i++)
            {
                if (method==1)
                {
                    if (array[left] > array[i])
                        swap(array,left,i);
                }else
                {
                    if (array[left] < array[i])
                        swap(array,left,i);
                }
            }
            
            for (int i=left+1;i<=right;i++)
            {
                if (method==1)
                {
                    if (array[right] < array[i])
                        swap(array,right,i);
                }else
                {
                    if (array[right] > array[i])
                        swap(array,right,i);
                    
                }
            }
            left++;
            right--;
        }
        return array;
    }
    
    /**
     * 快速排序方法,运用到递归
     * 排序原理:随机找到一个值,然后以此值大小进行分为两个数组,大的放左边,小的放右边,
     * 然后再对左右两侧的数据依次排序根据
     * @param array
     * @param method
     * @return
     */
    public static int[] quickOrder(int[] array, int method)
    {
        quickDeal(array,0,array.length - 1,method);
        return array;
    }

    /**
     *
     * @param array
     * @param begin
     *            开始位置
     * @param end
     *            结束位置
     */
    private static void quickDeal(int[] array, int begin, int end,int method) {
        if (end > begin) {
            int pos = begin + (int) (Math.random() * (end - begin + 1)); // 计算分隔位置
            int posvalue = array[pos]; // 取得分隔位置的值
            swap(array,pos,end); //将posvalue放到最end的位置
            pos=begin; //初始化pos
            for (int i=begin; i < end; i++) {
                if (method==1)
                {    
                    if (array[i] < posvalue) { //当小于posvalue时,将此值移动到pos位置,也就是向前移动
                        swap(array,pos,i);
                        pos++; //移动后pos增1
                    }
                }else if(method == 2)
                {
                    if (array[i] > posvalue) { //当小于posvalue时,将此值移动到pos位置,也就是向前移动
                        swap(array,pos,i);
                        pos++; //移动后pos增1
                    }
                }
            }
            swap(array,pos,end); //end位置的值前移
            quickDeal(array,begin,pos -1,method);
            quickDeal(array,pos+1,end,method);
        }

    }

    /**
     * 插入排序方法
     * 排序原理:抽出一个数,做为排序基序列,然后依次抽出其它数与,与此序列中的数进行比较,放入合适的位置
     * @param array
     * @param method
     * @return
     */
    public static int[] insertOrder(int[] array, int method) {

        for (int i = 1; i < array.length; i++) {
            if (method == 1) {
                if (array[i - 1] > array[i]) {
                    int tmp = array[i]; //
                    int j = i - 1;
                    do {
                        array[j + 1] = array[j];
                        j--;
                    } while (j >= 0 && tmp < array[j]); //当j>=0并且 当前值大于数据中j位置的值时移动
                    array[j + 1] = tmp; //插入排序值
                }
            } else if (method == 2) {
                if (array[i - 1] < array[i]) {
                    int tmp = array[i];
                    int j = i - 1;
                    do {
                        array[j + 1] = array[j];
                        j--;
                    } while (j >= 0 && tmp > array[j]);
                    array[j + 1] = tmp;
                }
            }
        }
        return array;
    }

    /**
     * 选择排序方法
     * 排序原理:每次选择一个最大的或最小的数放到已排序序列中
     * @param array
     * @param method
     * @return
     */
    public static int[] selectOrder(int[] array,int method)
    {
        for (int i=0;i<array.length - 1;i++)
        {
            int tmp = array[i];
            int pos = i+1; //记录大值或小值的位置 
            for (int j=i+1;j<array.length;j++)
            {
                if (method==1)
                {
                    if (array[j]<tmp)
                    {
                        tmp = array[j];
                        pos= j ;//记录大值或小值的位置
                    }
                }else if (method==2)
                {
                    if (array[j]>tmp)
                    {
                        tmp = array[j];
                        pos= j ;//记录大值或小值的位置
                    }
                }
            }
            if (tmp != array[i])
                swap(array,i,pos); //不相同时交换
        }
        return array;
    }

    
}

<think>好的,我现在需要解决用户的问题,即如何生成不同规模的顺序和随机整数序列,并在这些序列中使用不同的搜索算法找到最大的n个数。用户给出的N值包括500到50000的不同规模,而n是N的1/100。首先,我需要理清楚每个步骤的具体实现方法和可能遇到的挑战。 首先,生成顺序和随机序列。顺序序列应该是升序排列的,而随机序列则需要打乱顺序。需要注意的是,随机序列的生成要确保元素不重复,或者允许重复?用户没有明确说明,可能默认允许重复,但为了简单起见,我可以先生成顺序序列,然后打乱得到随机序列。例如,用Python的random.shuffle函数。 接下来,对于不同的搜索算法,用户提到了顺序搜索、折半搜索、二叉排序树、平衡二叉排序树。这里需要明确的是,用户可能希望比较这些算法在不同数据结构和数据分布下的性能差异。比如,顺序搜索在有序和无序情况下的效率,折半搜索只能用于有序序列,而二叉排序树和平衡树(如AVL树或红黑树)的构建及查询方法。 对于顺序搜索找最大的n个数,无论是顺序还是随机序列,通常需要遍历整个数组,记录最大的n个元素。但顺序序列如果是升序的,最大的n个数可以直接取最后n个元素,时间复杂度是O(1),而随机序列则需要O(N)的时间。不过用户提到的顺序搜索可能指的是线性搜索,不管数组是否有序,这可能会有误解。需要确认顺序搜索在这里的定义,如果是线性遍历找最大的n个,那么对于有序序列可能不需要全遍历,但用户可能希望统一处理,所以可能需要更明确的步骤。 对于折半搜索,这里可能是指二分查找,但如何应用在找最大的n个数?这可能不太直接。折半搜索通常用于查找特定元素,而不是找最大的n个数。或许用户想利用有序序列的特性,通过某种方式快速定位,但需要进一步思考。例如,在有序升序数组中,最大的n个数就是最后n个元素,直接切片即可,时间复杂度O(1),这可能不需要折半搜索。但用户可能误用了术语,或者这里的折半搜索有其他应用方式,可能需要澄清。或者,用户可能指的是使用二分法确定一个阈值,然后找出所有大于该阈值的数,但这需要多次二分查找,可能复杂度较高,尤其是当n较大的时候。 关于二叉排序树和平衡二叉排序树,构建这些树之后,如何找到最大的n个数?通常,二叉排序树的中序遍历可以得到升序序列,所以最大的n个数可以通过逆中序遍历取前n个节点。但这种方法需要遍历到足够的节点,时间复杂度取决于树的高度。对于平衡树来说,树的高度较低,因此效率更高。 接下来,针对不同的算法,需要设计具体的实现步骤,并分析其时间复杂度和空间复杂度。例如,顺序搜索在随机序列中可能需要维护一个大小为n的堆,每次比较新元素与堆的最小值,如果更大则替换,这样时间复杂度是O(N log n)。但在顺序序列中,可能直接取最后n个元素。 另外,用户提到的N值范围较大,尤其是到50000时,需要考虑算法的实际运行时间和内存占用。例如,生成50000个元素的数组在Python中是可行的,但构建二叉排序树可能会导致栈溢出或较高的内存消耗,尤其是在不平衡的情况下。 还需要考虑代码实现的正确性。例如,生成随机序列时是否需要保证唯一性?如果允许重复,直接生成即可;如果要求唯一,可能需要使用抽样方法。但用户的问题中没有特别说明,可以假设允许重复。 在代码实现方面,需要为每个算法编写函数,并测试其正确性。例如,顺序搜索可能使用最大堆或选择排序方法,而折半搜索可能不适用,需要进一步确认。 总结一下,我的思路是: 1. 生成顺序和随机序列:顺序序列是升序排列,随机序列通过打乱顺序生成。 2. 实现四种算法处理这两种序列,找到最大的n个数。 3. 对每个算法的时间复杂度进行分析,特别是在不同数据规模下的表现。 4. 编写Python代码示例,展示如何生成序列和应用算法。 5. 讨论不同算法的优缺点及适用场景,可能涉及引用中的内容,比如顺序查找的缺点和二叉排序树的构建方法。 可能遇到的问题: - 折半搜索如何应用在找最大的n个数?可能需要重新理解用户意图,或者用户可能有其他方法。 - 二叉排序树在随机数据下可能退化为链表,导致查找效率低下,而平衡树可以避免这个问题,如引用[4]提到的B树的高度影响查找效率,但这里可能指平衡二叉排序树如AVL树。 - 如何高效地找到最大的n个数?使用堆结构可能更高效,例如维护一个最小堆,保存当前最大的n个数,遍历整个数组时更新堆。 现在需要验证这些思路是否正确,特别是针对折半搜索的部分。可能用户在这里有误解,或者我需要调整思路。例如,在有序序列中找最大的n个数确实不需要折半搜索,直接取后n个即可。因此,用户可能将折半搜索作为其中一种方法,但实际在这种情况下可能并不适用,所以需要明确说明。 另外,用户可能希望比较不同数据结构在查找最大n个数时的效率,例如顺序查找需要O(N)时间,而二叉排序树可能需要O(N + n log N)时间(构建树的时间加上中序遍历的时间),平衡树可能更快,但构建时间也需考虑。 在代码示例部分,需要注意生成序列的函数,例如生成顺序序列为range(N),随机序列为shuffle后的列表。然后,对于顺序搜索,可以使用堆的方法;对于二叉排序树,需要实现树的构建和逆中序遍历。 此外,用户提供的引用内容中,引用[3]提到二叉排序树的插入和删除,引用[4]提到B树的复杂度,但用户的问题是关于平衡二叉排序树,可能需要调整引用到AVL树的相关内容,但引用中没有直接提及,可能需要调整引用标记的位置。 最后,需要生成相关问题,可能涉及不同算法的性能比较、优化方法、适用场景等,如用户示例中的问题形式。</think>### 分步解答 #### 一、生成整数序列的方法 1. **顺序序列**:生成$0$到$N-1$的升序排列数组,例如$N=500$时,序列为$[0,1,2,...,499]$。 2. **随机序列**:将顺序序列随机打乱。Python中可使用`random.shuffle()`实现。 #### 二、搜索算法的实现与复杂度分析 ##### 1. 顺序搜索(适用于随机序列) - **方法**:维护一个大小为$n$的最小堆,遍历所有元素。若当前元素比堆顶大,则替换堆顶并调整堆。 - **时间复杂度**:$O(N \log n)$,空间复杂度$O(n)$[^1]。 - **优化点**:若序列已有序(升序),直接取最后$n$个元素,时间复杂度$O(1)$。 ##### 2. 折半搜索(仅适用于有序序列) - **方法**:在有序序列中,直接截取最后$n$个元素。 - **时间复杂度**:$O(1)$(无需实际搜索,直接切片操作)。 ##### 3. 二叉排序树(BST) - **方法**: - 构建BST:将序列元素依次插入树中。 - 逆中序遍历:从右子树开始遍历,收集前$n$个最大值。 - **时间复杂度**:构建树$O(N \log N)$(平均情况),遍历$O(n)$。若树退化为链表,构建时间退化为$O(N^2)$[^3]。 - **空间复杂度**:$O(N)$。 ##### 4. 平衡二叉排序树(如AVL树) - **方法**:类似BST,但插入时通过旋转保持平衡。 - **时间复杂度**:构建树$O(N \log N)$,遍历$O(n)$。平衡树高度为$O(\log N)$,效率稳定[^4]。 #### 三、Python代码示例 ```python import random import heapq def generate_sequences(N): ordered = list(range(N)) shuffled = ordered.copy() random.shuffle(shuffled) return ordered, shuffled def sequential_search(arr, n): heap = [] for num in arr: if len(heap) < n: heapq.heappush(heap, num) else: if num > heap[0]: heapq.heappop(heap) heapq.heappush(heap, num) return sorted(heap, reverse=True) def binary_search_sorted(arr, n): return arr[-n:][::-1] class BSTNode: def __init__(self, val): self.val = val self.left = None self.right = None def build_bst(arr): root = None for num in arr: root = insert_bst(root, num) return root def insert_bst(root, val): if not root: return BSTNode(val) if val < root.val: root.left = insert_bst(root.left, val) else: root.right = insert_bst(root.right, val) return root def find_largest_bst(root, n): result = [] def reverse_inorder(node): if node and len(result) < n: reverse_inorder(node.right) if len(result) < n: result.append(node.val) reverse_inorder(node.left) reverse_inorder(root) return result # 示例:N=500,n=5 N = 500 n = N // 100 ordered, shuffled = generate_sequences(N) # 顺序搜索(随机序列) result_seq = sequential_search(shuffled, n) # 折半搜索(有序序列) result_bin = binary_search_sorted(ordered, n) # 二叉排序树 bst_root = build_bst(shuffled) result_bst = find_largest_bst(bst_root, n) ``` #### 四、性能对比与适用场景 | 算法 | 适用序列类型 | 时间复杂度 | 适用场景 | |------------------|--------------|------------------|----------------------------------| | 顺序搜索(堆) | 随机序列 | $O(N \log n)$ | 无需预处理,动态数据流 | | 折半搜索 | 有序序列 | $O(1)$ | 已排序数据的快速访问 | | 二叉排序树 | 随机序列 | $O(N \log N + n)$| 需要动态插入/删除操作 | | 平衡二叉排序树 | 随机序列 | $O(N \log N + n)$| 高频插入/删除且需稳定查询效率[^4]| #### 五、注意事项 1. **BST的退化问题**:随机序列可能使BST退化为链表,建议使用平衡树。 2. **内存限制**:当$N=50000$时,递归构建BST可能导致栈溢出,需改用迭代实现。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值