void CRemoteClientDlg::OnDownLoadFile()
{//这是一个文档的下载功能函数
//封装显示一组项的“列表视图控件”功能,每一项均包含一个图标(来自图像列表)和标签。
//这个m_list其实就是或者CListCtrl类我创建的一个变量,我通过这个东西去调用一系列的函数来获取对列表中下载文件的控制
int nListSelected = m_list.GetSelectionMark();
CString strFile = m_list.GetItemText(nListSelected, 0);
//CFileDialog封装用于文件打开操作或文件保存操作的常见对话框,如果点击了下载函数,那么这个API就会打开那个下载文件的窗口
CFileDialog dlg(FALSE, "*",
strFile,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
NULL, this);
//DoModal()表示的是显示对话框,用户可以做出选择
if (dlg.DoModal() == IDOK)
{
FILE* pFile = fopen(dlg.GetPathName(), "wb+");
if (pFile == NULL)
{
AfxMessageBox(_T("没有权限保存这个文件,或者文件是无法d打开"));
TRACE("执行下载命令失败: pFile = %d \r\n", pFile);
}
// HTREEITEM应该是获取文件树的东西,文档有点看不懂
HTREEITEM hSelected = m_tree.GetSelectedItem();
strFile = GetPath(hSelected) + strFile;
TRACE("%s \r\n", LPCSTR(strFile));
// typedef const char* LPCSTR;
//LPCSTR 是指向以 null 结尾的常量 32 位 Windows (ANSI) 字符字符串。
int ret = SendCommandPacket(4, false, (BYTE*)LPCSTR(strFile), strFile.GetLength());
if (ret < 0)
{
MessageBox("执行下载命令失败");
TRACE("执行下载命令失败: ret = %d \r\n", ret);
return;
}
//这一步是获取数据的长度
CClientSocket* pClient = CClientSocket::GetInstance();
long long nLength = *(long long*)pClient->GetPacket().strData.c_str();
if (nLength == 0)
{
MessageBox("文件的长度为0,或者无法读取文件");
TRACE("文件的长度为: nLength = %d \r\n", nLength);
return;
}
//用这个ncount来接受数据的长度并且下载的过程
long long nCount = 0;
while (nCount < nLength)
{
ret = pClient->DealCommand();
if (ret < 0)
{
MessageBox("文件传输失败");
TRACE("文件传输失败: ret = %d \r\n", ret);
break;
}
fwrite(pClient->GetPacket().strData.c_str(),
1, pClient->GetPacket().strData.size(), pFile);
nCount += pClient->GetPacket().strData.size();
}
fclose(pFile);
pClient->CloseSocket();
}
}
如果用暴力的解决方式的话,就是两个for循环直接暴力嵌套,然后对获取的数组去重操作就可以了。
如果用的是用数组来解决的话,因为这里给出的是数字,没有上限,所以开辟的数组的长度是不受限制的,在这里是非常容易造成数组空间的浪费。
此时就要使用另一种结构体了,set ,关于set,C++ 给提供了如下三种可用的数据结构:
std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的。
并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。
关于unordered_set的使用和内容
unordered_set - C++ Reference (cplusplus.com)
【C++进阶】八、STL—unordered_set & unordered_set的介绍及使用_c++ unordered_set_枫叶先生的博客-CSDN博客
- unordered_set 是不按特定顺序存储唯一元素的容器,允许基于它们的 key 快速检索单个元素
- 在 unordered_set 中,元素的值与唯一标识它的 key 同时存在,key 是不可变的,因此,unordered_set 中的元素在容器中不能被修改,但是它可以进行插入和删除
在内部,unordered_set 中的元素不按任何特定顺序排序,而是根据它们的哈希值插入到相应的桶中,允许直接根据它们的值快速访问单个元素(平均时间复杂度恒定,即常数O(1) )- Unordered_set 容器在通过键访问单个元素时比 set 容器更快,尽管它们在通过元素子集进行范围迭代时通常效率较低
- 容器中的迭代器至少是前向迭代器(只支持单向迭代器 ++)
unordered_set 会对插入重复的元素进行去重,即不允许插入相同的值
关于容器的使用,还是需要多多学习的,这是一个重点的内容
class Solution {
public:
vector intersection(vector& nums1, vector& nums2)
{
unordered_set result{};
unordered_set nums1_set(nums1.begin(),nums1.end());
for(int num : nums2)
{
if(nums1_set.find(num) != nums1_set.end())
{
result.insert(num);
}
}
return vector(result.begin(),result.end());
}
};
这个题目其实也可以用数组来解决,但是就像是笔记里面说的:
数组只适合范围比较小的时候的,如果给出的数值范围有1W的话,开辟一万空间大小的数组显然是很浪费的
class Solution {
public:
//这个其实会用很多关于容器的使用上的方式
vector intersection(vector& nums1, vector& nums2)
{
//这个用来存放最后的结果
unordered_set result{};
int hashArr[1000]{};
for (int num : nums1)
{
hashArr[num] = 1;
}
for (int num : nums2)
{
if (hashArr[num] == 1)
{
result.insert(num);
}
}
return vector(result.begin(), result.end());
}
};
看到一个用双指针的解决方式的想法,觉得还是挺大佬的思路的
第一遍看的时候没有看懂代码的意思,看了一伙儿之后绝对这种方式真的很牛逼
双指针
class Solution {
public:
//快慢指针的解决方式真的是天才了,看到这种解决办法觉真的挺不错的
int bitSum(int n)
{
int sum = 0;
while(n)
{
int bit = n%10;
sum += bit*bit;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
int fast = n;
int slow = n;
do{
slow = bitSum(slow);
fast = bitSum(fast);
fast = bitSum(fast);
}while(slow != fast);
return slow == 1;
}
};
哈希表
用哈希表的方式来解决问题
class Solution {
public:
int bitSum(int n)
{
int sum = 0;
while(n)
{
sum += (n%10)*(n%10);
n /= 10;
}
return sum;
}
bool isHappy(int n)
{
unordered_set result;
int sum = n;
while(1)
{
int res = bitSum(sum);
if(res == 1) return true;
if(result.find(res) != result.end())
{
return false;
}
result.insert(res);
sum = res;
}
}
};