链表问题首先要注意的,必须要注意的是题意:是否为空链表,是否有环,是否是单链表
链表节点的定义如下:
typedef struct list {
int key;
struct list *next;
}list;
已知链表的头结点head,写一个函数把这个链表逆序
关键点:1、是否是空链表;2、是否是循环链表,如果是完全循环链表(整个链表就是一个环),则直接逆序就行,如果不是却还有环,则没法逆序……
以下代码为未处理环的链表逆序
list * reverse(list * head) {
list * h = head;
list * new_head = NULL, *temp;
if (h==NULL) return h;//如果是空链表
do{
temp = h;
h = h -> next;
temp -> next = new_head;
new_head = temp;
} while(h != NULL && h != head) //检测是循环链表
return new_head;
}
已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)
关键点:各自有序是都是从大到小,即是否相同规格,如果不一样,则需要先将其中一个逆序
用递归方法进行的代码如下:
list * merge (list *list1_head, list *list2_head){
list * res;
if(list1_head == NULL) return list2_head;
if(list2_head == NULL) return list1_head;
if(list1_head->key > list2_head->key) {
res = list1_head;
res->next = merge(list1_head->next, list2_head);
} else {
res = list2_head;
res->next = merge(list1_head,list2_head->next);
}
return res;
}
写一个程序,计算链表的长度
unsigned int list_len(list *head){
unsigned int len = 0;
list * h = head;
if(h == NULL)return 0;
do {
len++;
h = h->next;
} while (h != NULL && h != head)
return len;
}
一个单向链表的头指针,可能循环链表(不是NULL结束),问怎么找出这个链表循环部分的第一个节点。
使用两个指针,一个为p1步长为1,另一个为p2步长为2,如果p2可以追上p1,则说明有环;
然后让p2固定,p1再来一圈,再与p2相遇时就能求出环的长度L;
然后令p1和p2都步长为1,从链表的头开始走,让他们间距为L,则第一个相等的地方,就是环的起点。
找出单向链表中的中间结点
利用步长为1,步长为2指针,当步长为2的指针到达末尾时,步长为1的指针就刚好达到中间(链表长度的奇偶性,注意处理边界)
给定单链表中的一个结点指针,在O(1)时间删除该结点。
将该节点的下一个节点的值copy到这个节点,然后删除下一个节点,注意如果要删除的是尾指针,即当前节点没有下一个节点(指向NULL),则直接置空
给定单链表中的一个结点指针p(非空),在p前面插入一个结点。
办法与前者类似,首先分配一个结点q,将q插入在p后,接下来将p中的数据copy入q中,然后再将要插入的数据记录在p中。
查找链表中倒数第k个结点
设置步长相同,间距为k的指针,其特点在当内存无法存放所有元素,需要从硬盘读取时,性能卓越,k在可以接受的情况下可以一次读取到内存,大大提高了效率。
注意考虑边界情况:如果链表的长度不足k,它就不存在k个元素,因此必须在两个指针的出发阶段检查最先出发的当前指针是否已经到了链表尾。
判断两个链表是否相交
只有一个链表有环的情况下是不会相交的,只有都有环或者都没有环的情况下才可能相交;
都没有环的情况下最简便的方法就是判断链尾是否相交即可;
都有环的情况下,分别找到环上的任一点,一个不动,另一个步进,即可判断是否相交
两个单向链表,开头结点不一样,在中间某处开始,结点一样了,找出它们的第一个公共结点。
可以通过判断最后一个节点是否相同,判断是否相交。如果相交,可以统计两个链表的长度,设一个为a,一个为b,然后这样再搞两个指针,一个先走|a-b|步,另一个再走,当它们相等时就是第一个公共结点。
链表排序
最好使用归并排序算法。堆排序、快速排序这些在数组排序时性能非常好的算法,在链表只能“顺序访问”的魔咒下无法施展能力,但是归并排序却如鱼得水,非但保持了它O(nlogn)的时间复杂度,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)
链表节点的定义如下:
typedef struct list {
int key;
struct list *next;
}list;
已知链表的头结点head,写一个函数把这个链表逆序
关键点:1、是否是空链表;2、是否是循环链表,如果是完全循环链表(整个链表就是一个环),则直接逆序就行,如果不是却还有环,则没法逆序……
以下代码为未处理环的链表逆序
list * reverse(list * head) {
list * h = head;
list * new_head = NULL, *temp;
if (h==NULL) return h;//如果是空链表
do{
temp = h;
h = h -> next;
temp -> next = new_head;
new_head = temp;
} while(h != NULL && h != head) //检测是循环链表
return new_head;
}
已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)
关键点:各自有序是都是从大到小,即是否相同规格,如果不一样,则需要先将其中一个逆序
用递归方法进行的代码如下:
list * merge (list *list1_head, list *list2_head){
list * res;
if(list1_head == NULL) return list2_head;
if(list2_head == NULL) return list1_head;
if(list1_head->key > list2_head->key) {
res = list1_head;
res->next = merge(list1_head->next, list2_head);
} else {
res = list2_head;
res->next = merge(list1_head,list2_head->next);
}
return res;
}
写一个程序,计算链表的长度
unsigned int list_len(list *head){
unsigned int len = 0;
list * h = head;
if(h == NULL)return 0;
do {
len++;
h = h->next;
} while (h != NULL && h != head)
return len;
}
一个单向链表的头指针,可能循环链表(不是NULL结束),问怎么找出这个链表循环部分的第一个节点。
使用两个指针,一个为p1步长为1,另一个为p2步长为2,如果p2可以追上p1,则说明有环;
然后让p2固定,p1再来一圈,再与p2相遇时就能求出环的长度L;
然后令p1和p2都步长为1,从链表的头开始走,让他们间距为L,则第一个相等的地方,就是环的起点。
找出单向链表中的中间结点
利用步长为1,步长为2指针,当步长为2的指针到达末尾时,步长为1的指针就刚好达到中间(链表长度的奇偶性,注意处理边界)
给定单链表中的一个结点指针,在O(1)时间删除该结点。
将该节点的下一个节点的值copy到这个节点,然后删除下一个节点,注意如果要删除的是尾指针,即当前节点没有下一个节点(指向NULL),则直接置空
给定单链表中的一个结点指针p(非空),在p前面插入一个结点。
办法与前者类似,首先分配一个结点q,将q插入在p后,接下来将p中的数据copy入q中,然后再将要插入的数据记录在p中。
查找链表中倒数第k个结点
设置步长相同,间距为k的指针,其特点在当内存无法存放所有元素,需要从硬盘读取时,性能卓越,k在可以接受的情况下可以一次读取到内存,大大提高了效率。
注意考虑边界情况:如果链表的长度不足k,它就不存在k个元素,因此必须在两个指针的出发阶段检查最先出发的当前指针是否已经到了链表尾。
判断两个链表是否相交
只有一个链表有环的情况下是不会相交的,只有都有环或者都没有环的情况下才可能相交;
都没有环的情况下最简便的方法就是判断链尾是否相交即可;
都有环的情况下,分别找到环上的任一点,一个不动,另一个步进,即可判断是否相交
两个单向链表,开头结点不一样,在中间某处开始,结点一样了,找出它们的第一个公共结点。
可以通过判断最后一个节点是否相同,判断是否相交。如果相交,可以统计两个链表的长度,设一个为a,一个为b,然后这样再搞两个指针,一个先走|a-b|步,另一个再走,当它们相等时就是第一个公共结点。
链表排序
最好使用归并排序算法。堆排序、快速排序这些在数组排序时性能非常好的算法,在链表只能“顺序访问”的魔咒下无法施展能力,但是归并排序却如鱼得水,非但保持了它O(nlogn)的时间复杂度,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)