线性表的部分就更到前面了,还有很多精彩的内容后面再补充进去吧,后面将会写链表、树、图,链表的第一部分:链表逆置是非常非常常考的内容,大家一定要重视呀!!
一、leetcode 206 简单的链表逆置
把一个链表逆置有两种思路,一种是不带头结点的,另一种使用虚拟头结点
其实两种算法本质没有区别,只是理解起来的思路不太一样,如果使用头结点,那我们可以按照头插法的思路去想,每次将这个结点从链表中取下来,再插入到虚拟头结点后面,那么这个循环的过程需要几步呢? 答:四步
while(p!=NULL){
temp=p->next;//暂存后面的链表,防止弄没
p->next-newhead->next ;//我们知道 插入将一个结点插入到一个链表中,要先修改后面的指针
newhead->next=p;//插入的第二步,成功建立联系
p=temp;//暂存了就要再赋值回来
}
那么用不构建头结点,就用指针如何来实现呢?本质还是一样的,四步,但是理解起来不太好想,设置pre指针的初值是NULL,这个指针永远代表逆置了的链表的头结点,每次操作完都要对其更新(实际上进行的逻辑上的前移)。比如pre=cur; 当然刚开始pre是NULL,工作指针的next也就是NULL了。
1 ->2->3->4的例子来演示
temp=2->3->4 第二次 temp=3->4; ` 第三次 temp=4
1->next=NULL; 2->next=1->NULL; 3->next=2->1->NULL
pre=1->NULL; pre=2->1NULL; pre=3->2>1
cur=2->3->4 cur=3->4 cur=4;
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur=head;
struct ListNode* pre=NULL;
struct ListNode* temp=NULL;
while(cur){
temp=cur->next;
cur->next=pre;//双指针思路 相当于让current上pre的列上去,产生关联
pre=cur;//pre指针代表的是反向链表的头结点,先把cur赋值过来,实际上实现了前移
cur=temp;//temp是为了让cur实现了后移
}
return pre;
}
二、leetcode 92反转部分链表
这个过程实际上就是,三大步 先把要反转的链表拆下来,然后将其反转,再将其插回到原链表中,因此前两个while循环是为了确定 链表拆下来的位置。再反转链表过程和插回中有两个注意事项写在了代码段中,很欢迎大家一起来讨论。
struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
struct ListNode* p=head;
struct ListNode*pre_i=NULL;
int i=left;
struct ListNode* after_j=head;
while(i>1){
pre_i=p;
p=p->next; //pre_i是i之前的第一个元素
i--;
}
int j=right;
while(j>0){
after_j==after_j=->next;//after_j=NULL;
j--; //after_j=是j以后的第一个元素
}
//以下为反转链表的部分
struct ListNode*pre=after_j=;//这里不能写NULL 不然会丢掉j以后的元素
while(p!=NULL&&right>=left){
struct ListNode* temp=NULL;
temp=p->next;
p->next=pre;
pre=p;
p=temp;
right--;
}
if(pre_i==NULL) return pre; //这是从头开始逆置的情况直接返回,因为pre——i为空
pre_i->next=pre;
return head;
}