您的位置:首页 > 其它

链表

2016-05-02 16:25 363 查看
链表的数据结构体:

struct node{
int data;
node* next;
node(int data = 0):data(data), next(0){}
};


带头结点的链表的创建:

node* create(int n){//带头结点的链表的创建
node* head = new node(), *p = head;
for(int i = 1; i <= n; i++){
p->next = new node(i);
p = p->next;
}
return head;
}


删除第n个结点:

void del(node* head, int n){
node* p = head, *q = head->next;
while(--n){
p = p->next;
q = q->next;
}
p->next = q->next;
free(q);
}


链表输出:

void show(node* head){
node* p = head->next;
while(p){
printf("%d ", p->data);
p = p->next;
}
puts("");
}


无头结点的反转:设置三个指针,从前往后扫。

void reverse(node*& head){//无头结点的反转
if(head == NULL||head->next == NULL)
return ;
node *p = head, *q = p->next, *ptr;
while(q != NULL){
ptr = q->next;
q->next = p;
p = q;
q = ptr;
}
head->next = NULL;
head = p;
return ;
}


带头结点的反转:设置三个指针,从前往后扫。

void reverse2(node*& head){//带头结点的反转
if(head == NULL||head->next == NULL)
return ;
node *p = head->next, *q = p->next, *ptr;
while(q != NULL){
ptr = q->next;
q->next = p;
p = q;
q = ptr;
}
head->next->next = NULL;
head->next = p;
return ;
}


反转中间某段:

Leetcode25. Reverse Nodes in k-Group

另起一个函数反转中间某段,注意指针为引用型。翻转的时候,依然需要三个指针。

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void inv(ListNode *&start, ListNode *&end){//reverse the node from start to end
ListNode *p = start, *m = p->next, *q = m->next;
start->next = end->next;
while(m != end){
m->next = p;
p = m;
m = q;
q = q->next;
}
m->next = p;
swap(start, end);
}
ListNode* reverseKGroup(ListNode* head, int k) {
if(k < 2) return head;
ListNode *p1 = head, *p2 = NULL;
for(int i = 1; i < k&&p1 != NULL; i++) p1 = p1->next;
if(p1 == NULL) return head;
p2 = p1->next;
inv(head, p1);
while(true){
p2 = p1->next;
for(int i = 1; i < k&&p2 != NULL; i++) p2 = p2->next;
if(p2 == NULL) return head;
inv(p1->next, p2);
p1 = p2;
}
}
};


——————————————————————————————————————

测试:

int main(){
node* head = create(10);
show(head);
del(head, 5);
show(head);
reverse2(head);
show(head);
return 0;
}


其他

问题1:删除不知头结点链表的某个节点

如果单向链表不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的节点?

思想为:把这个节点的下一个节点的值复制给该节点,然后删除下一个节点即可。

问题2:怎么判断链表中是否有环?

思想为:设置两个指针,一个步长为1,另一个步长为2,依次后移,如果相遇且都不为空,则有环。

问题3:如果一个单向链表,其中有环,怎么找出这个链表循环部分的第一个节点?

思想为:假设该节点在x位置处,假设步长为1的指针和步长为2的指针相遇在x处,

那么当一个指针再从头节点处以步长1递进时,另一指针从x点以步长1递进时,两个指针就会在循环开始处相遇。

简单证明:显然步长为2的指针多跑了k*循环长,而步长2跑的路程是步长1的两倍,则步长1跑了k*循环长。那么头节点和x节点离循环开始处距离相同。

问题4:如何查找链表中倒数第k个节点?

思想为:两个指向头结点的指针,一个先向后移动k位,然后两个同时向后面移动直到一个节点到达链尾,前面一个指针的位置就是了。

问题5:两个有序链表如何合并?

思想为:设两链表为La,Lb,设三指针pa,pb,pc。其中pa、pb指向两链表当前比较插入的结点,pc指向合并的链表的最后一个结点(初始状态可直接将其中一个链表 La 的头结点作为合并链表的尾结点)。

问题6:编程序判断两个链表是否相交。

如何知道两个单链表(无环)是否相交

如果两个单链表(无环)相交,如何知道它们相交的第一个节点是什么

如何知道两个单链表(有环)是否相交

如果两个单链表(有环)相交,如何知道它们相交的第一个节点是什么

    答案

这个问题的精彩解说请参见《编程之美》一书之《编程判断两个链表是否相交》,这里就不写了,该书的pdf文档在网上很好下。

文章后面给了两个扩展问题:

(1)如果链表可能有环,如何做判断?

思想为:首先应该明白,只有一个链表有环的情况下是不会相交的,只有都有环或者都没有环的情况下才可能相交,都没有环的情况下最简便的方法就是判断链尾是否相交即可;都有环的情况下,分别找到环上的任一点,一个不动,另一个步进,即可判断是否相交。

(2)如何求相交链表的第一个节点?应该为单链表情况

思想为:方法一是先把任一个链表连成环,即从表尾接到表头,按照问题4的解法;方法二是计算两个链表的长度,而两个链表是按照尾部对齐的,那么从短链表的第一个位置从长链表的第长度差+1的位置依次比较指针值,相等的位置即是。

关于链表的排序

O(n^2)算法从前往后扫,交换结点内的值。

O(nlogn)算法,O(1)插入删除(排序的时候,比参考点小,直接插入头节点前,否则插入尾节点后)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: