有关链表的理解:
初始化时head表示第一个节点:head->next表示第二个结点,head->val表示第一个节点的值,head->next->val表示第二个节点的值
head,head->next都是指针型数据
题目一:判断是否为环形链表
思路:沿着链表进行遍历,将遍历元素存入哈希表,并且判断哈希表中该元素是否存在即可:
class Solution {
public:
bool hasCycle(ListNode *head) {
//哈希表
unordered_set has;
while(head!=nullptr){
if(has.count(head)==1)return true;
has.insert(head);
head=head->next;
}
return false;
}
};
题目二:将两个升序链表进行合并
思路:采用递归的算法,注意空链表的情况。
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//递归
if(l1==nullptr)return l2;
if(l2==nullptr)return l1;
if(l1->val<=l2->val){
l1->next=mergeTwoLists(l1->next,l2);
return l1;
}
else{
l2->next=mergeTwoLists(l1,l2->next);
return l2;
}
}
};
题目三:删除链表中指定值的元素
思路:按照链表的删除操作将要删除的结点前一个节点指向它的后一个节点即可。注意头节点就要删除的情况所以新建一个指向头节点的节点。
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
struct ListNode* Head = new ListNode(0, head);
struct ListNode* temp = Head;
while (temp->next != NULL) {
if (temp->next->val == val) {
temp->next = temp->next->next;
} else {
temp = temp->next;
}
}
return Head->next;
}
};
四:辨析NULL和nullptr:
首先NULL是c语言的宏:
(宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的字符串,宏是用“#define"语句定义的,下面是一个宏定义的例子:#define VERSION—STAMP "1.02"):
#define NULL ((void*)0)将NULL定义为空指针。
解释((void*)0):
在c语言中,0是一个特殊的值,它可以表示:整型数值0,空字符,逻辑假(false)。表示的东西多了,有时候不好判断。尤其是空字符和数字0之间。为了明确的指出,0是空字符的含义,用用到了: ((void *) 0) 这个表达式。表示把0强制转换为空字符,不管以前代表的什么含义。
void*:void表示“无类型”,void *表示无类型指针。在定义指针的时候,必须声明指针的类型,因为类型决定了指针移动的字节数。定义为void*类型的指针可以任意替换为其他类型指针变量,其他类型指针变量之间不能进行此类操作:
double d=3.14;
double *dptr=&d;
int *iptr=dptr; //错误,double和int占用不同的字节,编译报错。
double d=3.14;
double *dptr=&d;
void *vptr=dptr //正确,无类型指针可以接受任何类型的指针。
由于c语言不支持函数重载,故在使用NULL时((void*)0)不会有指代歧义,但是c++支持函数重载,故在使用NULL时经常产生二义性造成编译错误,因此建议在c++中使用nullptr代替NULL。