for(int i=startx;i<n-offset;i++)
{
res[startx][i] = cout++;
}
在for循环时创建的i,在for循环结束后也销毁。
虚拟头节点的指向问题:
struct ListNode* swapPairs(struct ListNode* head) {
if (head == NULL) { // 空链表直接返回空
return NULL;
}
struct ListNode* virnode = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头结点
virnode->val = 0;
virnode->next = head;
struct ListNode* cur = virnode; // 遍历链表的指针cur
int i = 1;
while (cur->next&&cur->next->next) { // 只要cur->next不空或者不是一个结点的情况则继续遍历
struct ListNode* first = cur->next; // 指向第一个结点的指针
struct ListNode* second = cur->next->next; // 指向第二个结点的指针
cur->next = second; // 这里第一次遍历时会直接改变虚拟头结点的next的指向,它会指向链表新的第一个结点
cur = second; // 更新cur指针的位置使其指向第二个结点,同时这一步也使cur不再指向虚拟头结点,
//从而后续的遍历不会影响虚拟头结点next指向链表的第一个结点
struct ListNode* newnext = second->next; // 第二个节点后面的结点的地址
second->next = first; // 这里是两个结点进行交换的操作
first->next = newnext; // 将交换的后结点链接回原来的第二个结点的后续结点
cur = first; // 更新cur指针到新的遍历位置
} // 重复这个过程,这里可以通过上面图示自己走读一遍代码,标记好指针的位置即可
head = virnode->next;
return head;
}
链表结构是内存内部的一种存储方式,可以把链表结构想象成是一串节点,由若干个节点穿成一串的数据结构。每个节点都有两个区域:数据域和指针域。指针域指向下一个节点的地址。 链表节点的指针域和数据域都会占用内存。每个链表节点都包含两个部分:数据域和指针域。数据域存储节点的数据,指针域存储下一个节点的地址。因此,每个链表节点的内存占用量取决于数据域和指针域的大小。在C语言中,指针通常占用4个字节或8个字节,而数据域的大小则取决于数据类型。例如,如果数据域是一个整数,则占用4个字节;如果数据域是一个字符,则占用1个字节。总的来说,链表节点的内存占用量取决于数据域和指针域的大小,以及指针的大小。
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表无头节点就要单独对头节点处理,因为非头节点处理没有对第一个节点处理,而是接续对下一头节点处理。要判断头节点和下一节点是否为空,防止处理错误。
哈希表
哈希表是根据关键码的值而直接进行访问的数据结构。
哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。
当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
数组法需要知道问题占用空间大小,而且如果元素很少,而哈希值太大会造成内存空间的浪费,set不需要,可以继续插入。
将学生姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。
通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。
哈希冲突解决办法:
1、链表式解决
遇到冲突的时候,把数据写到next的位置。
2、开放地址
a 线性探测法
如果遇到冲突,新位置=原始位置+i(i是查找的次数)
b 平方探测(二次方探测)
如果遇到冲突,新位置=原始位置 + i平方(i为查找的次数)
c 双哈希
要设置第二个哈希的函数,例如hash2(key) = R - (key mod R)
R要取比数组尺寸小的质数。
如果遇到冲突,新位置=旧位置 + i*hash2(i为搜索次数)
std::unordered_set底层实现是哈希表,无序,查找高效
std::set和std::multiset底层实现是红黑树,是一种平衡二叉搜索树,key值有序,但key不能修改。std::multiset数值可以重复。
std::unordered_map底层实现是哈希表,std::map和std::multimap底层实现是红黑树。只有std::multimap的值可重复。
虽然std::set、std::multiset 的底层实现是红黑树,不是哈希表,std::set、std::multiset 使用红黑树来索引和存储,不过给我们的使用方式,还是哈希法的使用方式,即key和value。所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。 map也是一样的道理。
使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
n位数的每一位平方和代码:
int getsum(int n)
{
int sum=0;
while(n)
{
sum+= (n%10)*(n%10);
n /= 10;
}
return sum;
}
在C++中,使用大括号 {}
可以用于初始化一个容器,比如 std::vector
或者一个 std::array
。这种语法被称为初始化列表(initializer list)。
在这个特定的情况下,return {iter->second, i};
表示创建一个包含两个元素的 std::vector<int>
,其中第一个元素是 iter->second
,第二个元素是 i
。这样的语法在C++11及以后的标准中是合法的。
而在C++中,使用方括号 []
不会创建一个数组或者向量,而是用于访问数组或者向量的元素。所以 return [iter->second, i];
是不合法的C++语法。
总之,return {iter->second, i};
是用于返回一个包含两个整数的向量,而不是访问数组或向量元素的值。
sort方法
例如,对于输入的向量 nums = {3, -2, 1, -5, 4}
, 使用 nums.sort()
函数排序后,得到的结果是 { -5, -2, 1, 3, 4 }
,即负数在前,正数在后,而且每个数按照绝对值的大小进行排序。
使用map的空间消耗要比数组大一些,因为map要维护红黑树或者符号表,而且还要做哈希函数的运算。所以有时候数组更加简单直接有效!
std::map 和std::multimap 的key也是有序的
合法:for(int i=0, j=(s.size()-1);i < s.size()/2;i++,j--)
不合法:for(int i=0, int j=(s.size()-1);i < s.size()/2;i++,j--)
在 C++ 中,当你在 for 循环的初始化部分声明变量时,你不需要再次指定变量的类型,因为已经在声明的时候指定了。因此,在循环初始化的部分,你只需要写变量名和初始化值即可,不需要再次指定类型。这就是为什么 int j=(s.size()-1)
是合法的,而 int i=0, int j=(s.size()-1)
是不合法的。
一般库函数是左闭右开规则
栈与队列
st.pop()直接弹出栈顶元素,不能拿来比较,比较用top()函数。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> st;
for(int i=0;i<tokens.size();i++)
{
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/")
{
long long num1=st.top();
st.pop();
long long num2=st.top();
st.pop();
if(tokens[i] == "+") st.push(num1+num2);
if(tokens[i] == "-") st.push(num2-num1);
if(tokens[i] == "*") st.push(num1*num2);
if(tokens[i] == "/") st.push(num2/num1);
}
else
{
st.push(stoll(tokens[i]));
}
}
int result = st.top();
st.pop();
return result;
}
};
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/")里tokens的每个元素是vector<string>类型的,因此用""而不用字符型''
静态数组 int array[100] = {1}; //定义了数组array,并将数组第一个元素初始化为1,后面99个元素初始化为0;
数组初始化列表中的元素个数小于指定的数组长度时,不足的元素补以默认值。
注意如果在定义结构体变量的时候没有初始化,那么后面就不能全部一起初始化了;意思就
是:
/这样是可以的,在定义变量的时候就初始化了;
struct book s1={//对结构体初始化
"guojiajiaoyun",//author为字符数组
"yuwen",//title为字符串
22.5
};
/这种就不行了,在定义变量之后,若再要对变量的成员赋值,那么只能单个赋值了;
struct book s1;
s1={
"guojiajiaoyun",//author为字符数组
"yuwen",//title为字符串
22.5
};//这样就是不行的,只能在定义的时候初始化才能全部赋值,之后就不能再全体赋值了,只能单个赋值;
只能;
s1.title = "yuwen";........//单个赋值;
数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragmapack指定的数值和这个数据成员自身长度中,比较小的那个进行。
在C++标准库中,pop()
方法不是一个通用的数据结构方法。不同的数据结构有各自的特定方法来移除元素。这里是几个常见的数据结构及其对应的移除方法:
-
std::deque
(双端队列):pop_front()
: 移除前端的元素。pop_back()
: 移除后端的元素。
-
std::stack
(栈):pop()
: 移除栈顶元素。
-
std::queue
(队列):pop()
: 移除队列前端的元素。
-
std::priority_queue
(优先队列):pop()
: 移除队列顶端元素(最大或最小,取决于优先级定义)。