【问题标题】:Using quick sort to sort elements by frequency: how can I order elements of same frequency by size?使用快速排序按频率对元素进行排序:如何按大小对相同频率的元素进行排序?
【发布时间】:2021-04-27 09:22:59
【问题描述】:

我正在尝试使用快速排序在 Python 中解决这个问题:

给定一个整数数组 A[],根据元素的频率对数组进行排序。那就是频率较高的元素首先出现。如果两个元素的频率相同,那么较小的数字在前。

我创建了一个数组来存储A[]中每个整数出现的次数,如下:

def find_count(arr, n):
    count = [0]*(max(arr)+1)
    for i in arr:
        count[i] += 1
    return count

接下来,我使用快速排序来按出现次数的降序对元素进行排序:

def quicksort(arr, low, high, count):
    if(low < high):
        i = low
        j = high
        pivot = low
        while(i < j):
            while(i < high and count[arr[i]] >= count[arr[pivot]]):
                i += 1
            while(count[arr[j]] < count[arr[pivot]]):
                j -= 1
            if(i < j):
                arr[i], arr[j] = arr[j], arr[i]
        arr[pivot], arr[j] = arr[j], arr[pivot]
        quicksort(arr, low, j-1, count)
        quicksort(arr, j+1, high, count)

此方法用于按频率降序对元素进行排序。但是,频率相同的元素会以不可预知的顺序出现(不是按要求按大小递增的顺序):

For Input:
[5, 5, 4, 6, 4]
your output is: 
[5, 4, 4, 5, 6]
required output:
[4, 4, 5, 5, 6]

如何实现一个条件,以按大小递增的顺序对具有相同频率的元素进行排序?

【问题讨论】:

  • 你能解释一下你的输入和输出吗?为什么每个都不是整数数组?
  • 我处理了输入并将其转换为整数数组,并将输出数组转换为空格分隔的字符串。如果您有兴趣,我会发布该部分
  • @Shield77--我认为它是一个以空格分隔的字符串,但很困惑为什么事情在两行上。将它作为两行上的空格分隔整数我没有遵循排序顺序。首选的是输入数组(Python 列表)和所需的输出数组(Python 列表)。
  • 它们是两个不同的输入输出集,对于不够清晰表示抱歉。我将编辑以删除两者的第二行
  • @Shield77--两者都可以,但你应该评论它是两个测试用例。

标签: python arrays sorting


【解决方案1】:

您修改快速排序,使其使用键功能

  • 类似于 Python 排序函数使用键函数的方式
  • 更通用的解决方案,因为可以使用不同的键功能按其他标准排序

修改后的代码

def find_count(arr, n):
    count = [0]*(max(arr)+1)
    for i in arr:
        count[i] += 1
    return count

def quicksort(arr, low, high, keyfunc):
    if(low < high):
        i = low
        j = high
        pivot = low
        while i < j:
            while i < high and keyfunc(arr[i]) >= keyfunc(arr[pivot]):
                i += 1
            while keyfunc(arr[j]) < keyfunc(arr[pivot]):
                j -= 1
            if i < j:
                arr[i], arr[j] = arr[j], arr[i]
        arr[pivot], arr[j] = arr[j], arr[pivot]
        quicksort(arr, low, j-1, keyfunc)
        quicksort(arr, j+1, high, keyfunc)

测试

a = [5, 5, 4, 6, 4]
count = find_count(a, len(a))

# Use key function based upon tuple of count and value (use -v since want lower values first)
quicksort(a, 0, len(a)-1, lambda v: (count[v], -v)) 
# new a: [5, 5, 4, 6, 4]

# Change key function to sort strings
a = ['to', 'be', 'or', 'not', 'to', 'be', 'a', 'fool']
quicksort(a, 0, len(a)-1, lambda v: (-len(v), v))
# new a: ['a', 'to', 'to', 'or', 'be', 'be', 'not', 'fool']

【讨论】:

  • 谢谢,帮了大忙!
【解决方案2】:

我通过修改 quicksort() 函数解决了这个问题,如果它们的大小顺序错误,则只交换相同频率的元素:

def quicksort(arr, low, high, count):
if(low < high):
    i = low
    j = high
    pivot = low
    while(i < j):
        while(i < high and (count[arr[i]] > count[arr[pivot]] or
           (count[arr[i]] == count[arr[pivot]] and arr[i] <= arr[pivot]))):
            i += 1
        while( j >= low and count[arr[j]] < count[arr[pivot]] or
           (count[arr[j]] == count[arr[pivot]] and arr[j] > arr[pivot])):
            j -= 1
        if(i < j):
            arr[i], arr[j] = arr[j], arr[i]
    arr[pivot], arr[j] = arr[j], arr[pivot]
    quicksort(arr, low, j-1, count)
    quicksort(arr, j+1, high, count)

这样,我就可以根据需要的条件对数组进行排序了。

【讨论】:

    【解决方案3】:

    您创建地图并存储频率。现在使用快速排序对频率数组进行排序。交换频率数组时,也交换主数组元素。

    
    package javaapplication4;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class QuickSort {
    
        int arr[];
        int freq[];
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    
        QuickSort(int arr[]) {
            this.arr = arr;
            freq = new int[arr.length];
        }
     
        void qsortByFrequency(int low, int high) {
            if (low < high) {
    
                int pi = partitionByFrequency(low, high);
                qsortByFrequency(low, pi - 1);
                qsortByFrequency(pi + 1, high);
            }
        }
    
        int partitionByFrequency(int low, int high) {
            int pivot = freq[high];
            int i = low - 1;
            int j;
            for (j = low; j <= high; j++) {
                if (freq[j] < pivot) {
                    i++;
                    int temp = freq[i];
                    freq[i] = freq[j];
                    freq[j] = temp;
    
                    temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
            int temp = freq[i + 1];
            freq[i + 1] = freq[high];
            freq[high] = temp;
    
            temp = arr[i + 1];
            arr[i + 1] = arr[high];
            arr[high] = temp;
            return i + 1;
        }
    
        void getFrequency() {
    
            for (int i = 0; i < arr.length; i++) {
                if (map.containsKey(arr[i])) {
                    int c = map.get(arr[i]);
                    map.put(arr[i], ++c);
    
                } else {
                    map.put(arr[i], 1);
    
                }
            }
    
            for (int i = 0; i < this.arr.length; i++) {
                int el = arr[i];
                int c = map.get(arr[i]);
                freq[i] = c;
            }
    
            System.out.println("FreqMap " + map);
            this.qsortByFrequency(0, this.freq.length - 1);
    
        }
    
        void getSortedArray() {
    
            System.out.println(" Quick Sorted Array ");
            for (int i = 0; i < this.arr.length; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println(" -- ");
        }
    }
    

    【讨论】:

    • 虽然此代码可以回答问题,但提供有关 如何 和/或 为什么 解决问题的附加上下文将改善答案的长期价值。
    最近更新 更多