生成活动码,每次获取的记录不重复

批量生成与管理活动码的高效算法
本文介绍了一个用于批量生成、随机打乱顺序、并保存至文件的活动码生成算法,包括代码实现和执行流程说明。通过生成指定数量的活动码,实现其排序并最终写入文件,同时提供了获取并删除活动码的功能。

思路:1.生成活动码 2.随机打乱顺序 3.将生成的活动码对象(list)写入文件 4.每次获取记录并删除

未经同意不得转载闭嘴


package l_gen_numbers;



import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;


import org.springframework.util.StopWatch;
/**
 * 
 * 创建日期 : 2015-9-10
 * 类  描  述 : 生成活动码的类
 * 修改历史 : 
 *     1. [2015-9-10]创建文件 by shisiyuan
 */
public class Generator {
private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz").toCharArray();
private static int len = numbersAndLetters.length;
public static String FILE_NAME = "d:\\Generator.txt";
public static void main(String[] args) throws FileNotFoundException, IOException {
StopWatch clock = new StopWatch();// 统计执行时间

// 1.生成号码
clock.start("generator");
List<String> result = gen();
clock.stop();
// 2.随机打乱顺序,i代表次数。现在只设置了一次,可以修改为多次,执行时间比较长,每次在本机差不多5分钟
clock.start("change");
for(int i=0;i<1;i++){
result = change(result);
}
clock.stop();
// // 3.存入文件
clock.start("writeToFile");
writeToFile(result);
clock.stop();
System.out.println(clock.prettyPrint());

long size = len*(len-1)*(len-2)*(len-3)*(len-4)*(len-5)/6/5/4/3/2l;
        System.out.println("排列数长度:"+size);
        System.out.println("活动码长度:"+result.size());
}

public static void writeToFile(List<String> result) throws FileNotFoundException, IOException{
   writeToFile(result, FILE_NAME);
}


// 写入文件
public static void writeToFile(List<String> result, String fileName) throws FileNotFoundException, IOException {
   System.out.println("写入文件开始,活动长度"+result.size()+"....");
   ObjectOutputStream out = null;
   try {
       File file = new File(fileName);
       if(file.exists()){
           file.delete();
       }
       out = new ObjectOutputStream(new FileOutputStream(file));
       out.writeObject(result);
        } finally {
            if(out!=null){
                out.close();
                out = null;
            }
            System.out.println("写入文件结束....");
        }
}


/**
* 随机打乱顺序
*/
public static List<String> change(List<String> list) {
System.out.println("随机打乱顺序执行中,请不要中断....");
List<String> result = new ArrayList<String>();
int size = list.size();
Random random = new Random(size);
List<Integer> indexes = new ArrayList<Integer>();
for (int i = 0; i < size; i++) {
int index = random.nextInt(size-i);

indexes.add(index);

list.get(index)

}


for(int index : indexes){
result.add(list.get(index));
}

System.out.println("随机打乱顺序完成....");
return result;
}


/**
* 生成活动码
*/
public static List<String> gen(){
   System.out.println("生成活动码执行中....");
List<String> result = new ArrayList<String>();
int length = 6;
StringBuilder sb = null;
for(int i1=0;i1<=len-length;i1++){
for(int i2=i1+1;i2<=len-length+1;i2++){
for(int i3=i2+1;i3<=len-length+2;i3++){
for(int i4=i3+1;i4<=len-length+3;i4++){
for(int i5=i4+1;i5<=len-length+4;i5++){
for(int i6=i5+1;i6<=len-length+5;i6++){
sb = new StringBuilder();
sb.append(numbersAndLetters[i1])
.append(numbersAndLetters[i2])
.append(numbersAndLetters[i3])
.append(numbersAndLetters[i4])
.append(numbersAndLetters[i5])
.append(numbersAndLetters[i6]);
result.add(sb.toString());
}
}
}
}
}
}
        System.out.println("生成活动码执行完成....");
return result;
}


}


package l_gen_numbers;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;


/**
 * 创建日期 : 2015-9-10
 * 类  描  述 : 获取活动码的类
 * 修改历史 : 
 *     1. [2015-9-10]创建文件 by shisiyuan
 */
public class Fetcher {
    
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        List<String> list = fetchAndDelete(10000);
        String filePath = "D:\\fetcher.txt";
        writeStringToFile(list, filePath);
        System.out.println("获取的活动码长度:"+list.size()+",请查看:"+filePath);
    }


    
    private static void writeStringToFile(List<String> list, String filePath) throws IOException {
        BufferedWriter writer = null;
        try {
            File file = new File(filePath);
            if(file.exists()){
                file.delete();
            }
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
            for(String code : list){
                writer.write(code+"\r\n");
            }
        } finally {
            if(writer!=null){
                writer.close();
                writer = null;
            }
        }
        
    }




    @SuppressWarnings("unchecked")
    public static List<String> fetchAndDelete(int count) throws FileNotFoundException, IOException, ClassNotFoundException{
        System.out.println("获取活动码开始,请不要中断...");
        List<String> result = new ArrayList<String>();
        ObjectInputStream in = null;
        try {
            // 1.获取数据
            in = new ObjectInputStream(new FileInputStream(Generator.FILE_NAME));
            List<String> numbers = (List<String>) in.readObject();
            for(int i=0;i<count;i++){
                result.add(numbers.remove(i));
            }
            // 2.将删除后的数据重新写到文件中
            Generator.writeToFile(numbers);
        } finally {
            if(in!=null){
                in.close();
                in = null;
            }
        }
        System.out.println("获取活动码结束,请查看...");
        return result;
    }
}

<think>我们被要求生成重复的随机数。在MFC中,我们可以使用标准的C++随机数生成方法,但需要确保重复。常见方法:1.使用洗牌算法(Shuffle)来生成一个序列,然后按顺序取出,这样就重复。适用于需要生成一组重复随机数的场景。2.如果需要生成多个重复的随机数,我们可以先创建一个包含所有可能数值的数组,然后打乱这个数组,再依次取出。3.如果随机数的范围很大(例如生成1到10000之间的100个重复随机数),我们可以使用集合(set)来记录已经生成的随机数,每次生成一个新的随机数,检查是否在集合中,如果存在则重新生成,直到生成一个在集合中的数。但这种方法在需要生成的随机数数量接近范围总数时效率会降低(因为冲突概率增加)。根据引用资料,MFC中生成随机数的方法通常是使用srand和rand函数(如引用[3][4][5]所示)。但是,这些引用并没有直接提供生成重复随机数的方法。因此,我们将结合洗牌算法和集合检查两种方法,根据实际需求选择。方法一(洗牌算法):步骤:a.确定随机数的范围(例如,从0到N-1)。b.创建一个数组,按顺序填充0到N-1。c.使用随机数生成器来打乱这个数组(洗牌)。d.然后按顺序从数组中取出,即可得到重复的随机数序列。方法二(使用集合):a.初始化一个空集合。b.循环直到生成所需数量的随机数:生成一个随机数如果这个随机数在集合中,则将其加入集合(并记录到结果中),否则重新生成。根据问题,我们需要在MFC中实现。由于MFC是基于C++的,我们可以使用标准模板库(STL)中的vector和set,以及随机函数。注意:在MFC中,我们可以使用CArray等类,但使用STL更为方便。我们以生成0到99之间的10个重复随机数为例:方法一示例代(洗牌算法):#include<algorithm>#include<vector>#include<cstdlib>#include<ctime>std::vector<int>generateUniqueRandom(intmin,intmax,intcount){//如果要求生成的随机数数量超过范围,则只能生成范围内的所有数intrange=max-min+1;if(count>range){//可以调整count为range,或者返回错误count=range;}//创建并填充数组std::vector<int>numbers;numbers.reserve(range);for(inti=min;i<=max;i++){numbers.push_back(i);}//洗牌std::srand(static_cast<unsignedint>(std::time(nullptr)));std::random_shuffle(numbers.begin(),numbers.end());//取前count个returnstd::vector<int>(numbers.begin(),numbers.begin()+count);}注意:C++11中推荐使用<random>库,但考虑到MFC项目可能使用较旧的编译器,我们使用std::random_shuffle(在C++14中已被废弃,C++17中移除)。如果使用新标准,可以使用std::shuffle。方法二示例代(使用集合):#include<set>#include<vector>#include<cstdlib>#include<ctime>std::vector<int>generateUniqueRandom(intmin,intmax,intcount){std::set<int>uniqueNumbers;std::vector<int>result;intrange=max-min+1;if(count>range)count=range;std::srand(static_cast<unsignedint>(std::time(nullptr)));while(uniqueNumbers.size()<static_cast<size_t>(count)){intnum=min+rand()%range;if(uniqueNumbers.find(num)==uniqueNumbers.end()){uniqueNumbers.insert(num);result.push_back(num);}}returnresult;}在MFC中,我们可以将上述代封装成一个函数,并在需要的地方调用。例如,在按钮点击事件中调用,并将结果显示在编辑框中。但是,注意在MFC中,我们通常使用CString来显示字符串,所以可能需要将生成的随机数转换为字符串并显示。根据引用[4]中的代,我们可以看到如何在MFC中操作文件、编辑框等。我们可以参考其方式。具体步骤:1.在对话框类中,为按钮添加事件处理程序。2.在事件处理程序中,调用生成重复随机数的函数。3.将生成的随机数显示在编辑框或列表中。我们以方法一(洗牌算法)为例,在MFC中实现:假设我们有一个编辑框(IDC_EDIT_COUNT)用于输入要生成的随机数个数,一个列表框(IDC_LIST_RESULT)用于显示结果。在按钮点击事件处理函数中:voidCMyDlg::OnBnClickedButtonGenerate(){CStringstrCount;GetDlgItemText(IDC_EDIT_COUNT,strCount);intcount=_ttoi(strCount);//设置随机数范围,例如0到99intmin=0;intmax=99;//生成重复随机数std::vector<int>randomNumbers=generateUniqueRandom(min,max,count);//清空列表框CListBox*pList=(CListBox*)GetDlgItem(IDC_LIST_RESULT);pList->ResetContent();//将随机数添加到列表框for(intnum:randomNumbers){CStringstr;str.Format(_T("%d"),num);pList->AddString(str);}}注意:需要包含头文件<vector>和<algorithm>,以及初始化随机种子(在程序开始时初始化一次即可,例如在对话框的OnInitDialog中调用srand)。但是,上面的generateUniqueRandom函数使用了std::random_shuffle,这个函数在较新的编译器中可能被移除。因此,我们可以自己实现洗牌算法或者使用std::shuffle(需要C++11)。如果使用C++11,我们可以这样写:#include<random>#include<algorithm>std::vector<int>generateUniqueRandom(intmin,intmax,intcount){intrange=max-min+1;if(count>range)count=range;std::vector<int>numbers;numbers.reserve(range);for(inti=min;i<=max;i++){numbers.push_back(i);}std::random_devicerd;std::mt19937g(rd());std::shuffle(numbers.begin(),numbers.end(),g);returnstd::vector<int>(numbers.begin(),numbers.begin()+count);}然而,如果项目支持C++11,我们可以自己写一个简单的洗牌:for(inti=range-1;i>0;--i){intj=rand()%(i+1);std::swap(numbers[i],numbers[j]);}因此,我们可以修改为:std::vector<int>generateUniqueRandom(intmin,intmax,intcount){intrange=max-min+1;if(count>range)count=range;std::vector<int>numbers;numbers.reserve(range);for(inti=min;i<=max;i++){numbers.push_back(i);}//洗牌for(inti=range-1;i>0;--i){intj=rand()%(i+1);//生成[0,i]之间的随机索引std::swap(numbers[i],numbers[j]);}//取前count个returnstd::vector<int>(numbers.begin(),numbers.begin()+count);}注意:在调用这个函数之前,需要初始化随机种子(srand)。在对话框初始化时(OnInitDialog)调用一次srand即可。在MFC中,我们可以在对话框类的初始化函数中初始化随机种子:BOOLCMyDlg::OnInitDialog(){CDialogEx::OnInitDialog();//...其他初始化srand(static_cast<unsignedint>(time(nullptr)));returnTRUE;}这样,每次启动程序时,随机种子会被设置一次。总结:根据需求,我们提供了使用洗牌算法生成重复随机数的方法,并给出了在MFC中的实现步骤和示例代。注意:如果生成的随机数范围很大(例如0到999999),而只需要少量(比如10个)重复随机数,那么洗牌算法会占用大量内存(创建一个1000000个元素的数组)。在这种情况下,使用方法二(使用集合)更合适。因此,我们可以根据范围大小和需要生成的数量来选择方法。这里我们提供一个更通用的函数,根据范围大小自动选择方法(当范围太大时,使用集合方法;当范围适中时,使用洗牌算法)。但为了简单起见,我们通常根据实际情况选择一种方法。由于问题中没有指定范围大小和数量,我们默认使用洗牌算法(当范围合理时)。最后,我们生成相关问题:</think>### MFC生成重复随机数的方法 在MFC中生成重复随机数的核心思路是结合**洗牌算法**和**集合验证**机制。以下是具体实现方法: #### 方法一:洗牌算法(推荐) ```cpp #include <algorithm> #include <vector> // 生成重复随机数序列 std::vector<int> GenerateUniqueRandom(int minVal, int maxVal, int count) { std::vector<int> numbers; int range = maxVal - minVal + 1; // 1. 创建有序序列 for (int i = minVal; i <= maxVal; ++i) { numbers.push_back(i); } // 2. 随机洗牌(Fisher-Yates算法) srand(static_cast<unsigned>(time(nullptr))); for (int i = range - 1; i > 0; --i) { int j = rand() % (i + 1); std::swap(numbers[i], numbers[j]); } // 3. 截取所需数量 if (count > range) count = range; return std::vector<int>(numbers.begin(), numbers.begin() + count); } // MFC按钮事件调用示例 void CMyDlg::OnBnClickedGenerate() { std::vector<int> randNums = GenerateUniqueRandom(1, 100, 10); // 生成1-100间10个重复数 CString strResult; for (int num : randNums) { strResult.AppendFormat(_T("%d "), num); } SetDlgItemText(IDC_EDIT_RESULT, strResult); } ``` **优点**:时间复杂度 $O(n)$,效率高,无重复风险[^1] #### 方法二:集合验证法 ```cpp #include <set> std::vector<int> GenerateUniqueRandom(int minVal, int maxVal, int count) { std::set<int> uniqueSet; std::vector<int> result; int range = maxVal - minVal + 1; srand(static_cast<unsigned>(time(nullptr))); while (uniqueSet.size() < static_cast<size_t>(count)) { if (uniqueSet.size() >= static_cast<size_t>(range)) break; int num = minVal + rand() % range; if (uniqueSet.find(num) == uniqueSet.end()) { uniqueSet.insert(num); result.push_back(num); } } return result; } ``` **适用场景**:随机数范围极大(如 0-1000000)但只需少量重复值[^2] #### 关键注意事项 1. **随机种子初始化** 在程序初始化处调用:`srand((unsigned)time(NULL));` (只需执行一次,通常放在`OnInitDialog()`中) 2. **范围有效性检查** ```cpp if (maxVal < minVal || count <= 0) { AfxMessageBox(_T("无效的随机数范围")); return {}; } ``` 3. **MFC界面绑定** 使用`SetDlgItemInt()`或`CListBox::AddString()`显示结果 4. **大范围优化** 当范围超过10000时,推荐使用方法二避免内存浪费 > 两种方法均通过预先生成候选集或动态验证机制确保唯一性,可满足抽奖、唯一ID生成、随机采样等场景需求[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值