关于单链表的一些操作
1.删除一个节点:
若给定了被删除节点之前的节点,则可以改变前节点的指向,并释放后节点即可
代码实现:
struct listnode * delect(struct listnode * head)
{
struct listnode * use = head -> next ;
head -> next = head -> next -> next ;
free(use);
return head;
}
若值给定了被删除节点,则无法改变前节点的指向,同时也无法移动后节点的地址,但是我们可以将后节点的内容拷贝并覆盖在当前节点上在释放后节点,达到删除节点的效果。
代码实现:
void * delect(struct listnode * det)
{
struct listnode * temp = det -> next;
*(det) = *(det -> next) ;//将后节点的内容复制并覆盖
free(temp);
return ;
}
2.寻找中间节点
运用快慢指针的方法,快指针一次走两步,慢指针一次走一步,直到快指针走到尾节点时停止,此时慢指针指向的就是链表的中间位置。
运用此方法也可以寻找三分之一点,四分之一点等,但是要注意边界条件和不能越界。
代码实现:
struct listnode * mid(struct listnode * head)
{
struct listnode * fast = head;
struct listnode * slow = head;
while(fast != NULL && fast -> next != NULL) //确保一次走两步不越界
{
fast = fast -> next -> next;
slow = slow -> next ;
}
return slow ;
}
3.反转一个单链表
可以运用递归的方法,利用系统堆栈暂时存储各节点的地址并依次反转
代码实现:
struct listnode * reverse(struct listnode * head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct listnode * newhead = reverse(head -> next);
head -> next -> next = head;
head -> next = NULL;
return newhead;
}
也可以使用头删加头插法,对原链表进行头删,对新链表进行头插即可。
代码实现:
struct listnode * reverse(struct listnode * head)
{
struct listnode * newhead = NULL;
struct listnode * node ;
while(head != NULL)
{
node = head ; //暂时存储被头删的节点
head = head -> next;//原链表头删
node -> next = newhead;//新链表头插
newhead = node;//更新链表头
}
return newhead;
}
当然也可以使用三个指针依次改变链表的指向。
代码实现:
struct listnode * reverse(struct listnode * head)
{
struct listnode * cur = head ;
struct listnode * pre = null;
struct listnode * then = head ;
while(cur != null)
{
then = cur -> next;
cur -> next = pre;
pre = cur ;
cur = then;
}
return pre;
}
4.归并两个有序链表:
利用归并排序的思想,不过与归并排序不同的是,链表的归并并不需要复制出一个等长的链表,只需要一个新的头节点即可。
代码实现:
struct listnode * merge(struct listnode * head1,struct listnode * head2)
{
struct listnode * newhead = (struct listnode *)(malloc(sizeof(struct listnode))) ;
struct listnode * ret = newhead;
newhead -> val = 0;
newhead -> next = null;
while(head1 != NULL && head2 != NULL)
{
if(head1 -> val < head2 -> val)
{
newhead -> next = head1;
head1 = head1 -> next;
}
else
{
newhead -> next = head2;
head2 = head2 -> next;
}
newhead = newhead -> next ;
}
while(head1 != NULL)
{
newhead -> next = head1;
head1 = head1 -> next ;
newhead = newhead -> next;
}
while(head2 != NULL)
{
newhead -> next = head2;
head2 = head2 -> next ;
newhead = newhead -> next;
}
return (ret -> next) ; //排除新增的头节点
}
> 更复杂的操作均可以使用以上的基础操作组合实现,比如实现链表的排序就可以使用归并排序的思想 :
struct ListNode * merge(struct ListNode * head1,struct ListNode * head2)
{
struct ListNode * ret = (struct ListNode * )(malloc(sizeof(struct ListNode))) ;
struct ListNode * use = ret ;
struct ListNode * p1 = head1 ;
struct ListNode * p2 = head2 ;
while(p1 != NULL && p2 != NULL)
{
if( p1 -> val <= p2 -> val)
{
use -> next = p1;
p1 = p1 -> next;
}
else
{
use -> next = p2;
p2 = p2 -> next;
}
use = use -> next;
}
while(p1 != NULL)
{
use -> next = p1;
p1 = p1 -> next;
use = use -> next;
}
while(p2 != NULL)
{
use -> next = p2;
p2 = p2 -> next;
use = use -> next;
}
return (ret->next);
}
struct ListNode * mergesort(struct ListNode * head,struct ListNode * end)
{
if(head == NULL)
return head;
if(head -> next == end)
{
head -> next = NULL;
return head;
}
struct ListNode * fast = head;
struct ListNode * slow = head;
while(fast != end && fast -> next != end)
{
fast = fast -> next -> next;
slow = slow -> next;
}
return merge(mergesort(head,slow),mergesort(slow,end));
}
在递归处理时务必关注边界条件和入参的改变,比如在mergesort()函数中寻找中点时就需要改变判断条件,不然会报错
> 判断回文链表,就可以通过寻找中点+链表逆置+遍历判断
代码实现:
bool isPalindrome(struct ListNode* head){
struct ListNode * fast = head -> next;
struct ListNode * slow = head;
struct ListNode * newhead = NULL;
bool ret = true;
//if(slow == NULL || fast == NULL)
// return true; 此处特殊情况被包括进了下面的一般循环判断之中
while(fast != NULL && fast -> next != NULL)
{
slow = slow -> next;
fast = fast -> next -> next;
}
newhead = reverse(slow -> next) ;
while(ret && newhead != NULL) //当只要有一个为假时,立即跳出循环,并设 //置返回值
// 此处通过分析可以发现只要确保第二段链表的尾节点不为空,那么第一段的节点也不会为空
{
if(head -> val != newhead -> val)
ret = false ;
head = head -> next;
newhead = newhead -> next;
}
return ret;
}