首先积分值有个最大值,积分由n变化到m 排名变化的只是在积分n到积分m的客户排名会发生变化故此 有如下实现 使用RankAndNum来表示处在该积分的排名和数值 使用RankAndNums数值来保存所有积分排名(注意:RankAndNums[n]中RankAndNum中的rank和Num则表示积分为n的排名和处在积分为n的用户数量) 看下面积分改变时注意自己画图理解,积分由n上升到m时位于n到m(不包括m)中积分的排名(如果该位置已经有排名)都会降低一位; 其他情况也是类似 下面上代码: /** * 该类主要用于现有积分排名策略 能够迅速感知积分排名的变化; * 而时间复杂度又不至于过高。 * <p> * 该算法在计算时需要考虑变化之后,原来位置有没有积分排名,变化后原位置是否有积分排名, * 是否应该清楚该积分排名等操作。是不是首位,末尾等提示。 */ public class paiming { private int MAX_SCORE = 10; //默认100 private RankAndNum[] rankAndNums = new RankAndNum[MAX_SCORE]; //初始化rank public void init() { for (int i = 0; i < rankAndNums.length; i++) { rankAndNums[i] = new RankAndNum(0, 0); } } public static void main(String[] args) { paiming p = new paiming(); int[] array = new int[]{1, 7, 3, 5, 9, 2, 8}; array =p.getArray(array);//排序获得有序的数组 使用的是堆排序, p.init(); //给现有的积分进行排名 p.getRanking(array); p.getRecentRanking(7, 0); for (int i = 0; i < 10; i++) { System.out.print(p.rankAndNums[i].rank); System.out.println(p.rankAndNums[i].Num); } //int t = p.find(array, 0, array.length - 1, 7); //System.out.print(t); } //首先进行排序 从0开始为根节点, public void minHeap(int[] array, int start, int end) { int j = 2 * start + 1; //左做节点 int tmp = array[start]; int length = end; while (j <= length) { if (j + 1 <= length && array[j + 1] <array[j]) { j++; } if (array[j] < tmp) { array[start] = array[j]; start = j; j = 2 * start + 1; } else { break; } } array[start] = tmp; } //构建最小堆 /** * 使用的是堆排序,每次出最小放在数组末端,因此t表示未处理的最后下标 * * @param array 目标数组 * @param end 为处理数据的最后下标 */ public void heapAdjust(int[] array, int end) { for (int j = end / 2; j >= 0; j--) { minHeap(array, j, end); } } public int[] getArray(int[] array) { for (int i = array.length - 1; i > 0; i--) { heapAdjust(array, i); swap(array, 0, i); } return array; } public void swap(int[] array, int i, int j) { int tmp = array[i]; array[i] = array[j]; array[j] = tmp; } //获得积分排名 使用rank来保存 并(存在分数相同的情况),因为已经有序 但注意到积分可能会相同 //这个时候取前面的数组下表为积分排名 public void getRanking(int[] array) { for (int i = 0, j = 0; i < array.length; i++) { if (i - 1 > 0 && array[i - 1] == array[i]) { rankAndNums[array[i - 1]].Num++; continue; } rankAndNums[array[i]].rank = i + 1; rankAndNums[array[i]].Num = 1; } } //假设积分发生变动,某用户由n积分 ,变为 m积分,m,n都为正整数; public void getRecentRanking(int n, int m) { rankAndNums[n].Num -= 1; //变更后对应积分数量减一 rankAndNums[m].Num += 1; //变更后对应积分数量加一 if (m > n) { //积分增加 if (rankAndNums[m].rank == 0) { //若变更后的位置没有排名 int next = -1; //判断变更后的前一个积分排名,若有则会指向他 没有则为-1,默认没有 for (int i = n; i < m; i++) { if (rankAndNums[i].Num != 0) { next = i; rankAndNums[i].rank += 1; } } if (next == -1) { //当pervious=-1是说明他们间的积分全都没有排名, rankAndNums[m].rank = rankAndNums[n].rank; } else { rankAndNums[m].rank = rankAndNums[next].rank - 1; } } else { //变更后原来位置本来就有人 for (int i = n; i < m; i++) { if (rankAndNums[i].Num != 0) { rankAndNums[i].rank += 1; } } } if (rankAndNums[n].Num == 0) { rankAndNums[n].rank = 0; } } else if (m < n) { //积分减少 int previous = -1; //判断前一个是否有排名积分 for (int i = n - 1; i >= m; i--) { if (rankAndNums[i].rank != 0) { //这里注意别用Num属性值判断 应为变更后m出不管有没有 //Num数值都是大于0的; previous = i; rankAndNums[i].rank -= 1; } } //对排名m另做处理 if (previous == -1) {//m到n之间别的积分没占排名 if (rankAndNums[n].Num != 0) { //n位置不为空 rankAndNums[m].rank = rankAndNums[n].rank + rankAndNums[n].Num; } else { //n位置为空 rankAndNums[m].rank = rankAndNums[n].rank; } } else if(previous == m){ }else { rankAndNums[m].rank = rankAndNums[previous].rank + rankAndNums[previous].Num; } if (rankAndNums[n].Num == 0) { // 原先位置没有了人 不该有排名 rankAndNums[n].rank = 0; } } else { //积分没变 return; } } // (递归查找有没有) /** * 本函数主要用于查找已在array中的元素,不存在查找不到的情况 * * @param array 目标数组 * @param left 起始位置 * @param right 终止位置 * @param target 查找对象 * @return 排名 */ private int find(int array[], int left, int right, int target) { int pos = (left + right) / 2; if (right >= left) { if (target > array[pos]) { return find(array, pos + 1, right, target); } else if (target < array[pos]) { return find(array, left, pos - 1, target); } else { return pos; } } return -1; } //查找最后一个大于自己的数的下标即为现在排名 }
海量积分排名 简化后的具体实现
最新推荐文章于 2023-09-23 10:55:06 发布