链表

链表的数据结构体:

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

链表反转:设置三个指针,从前往后扫。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode * reverseList(ListNode *head) {
        if(head == NULL || head->next == NULL) return head;
        ListNode *p1 = head, *p2 = p1->next;
        p1->next = NULL;
        while(p2) {
            ListNode *p3 = p2->next;
            p2->next = p1;
            p1 = p2;
            p2 = p3;
        }
        return p1;
    }
};

反转中间某段:

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;
        }
    }
};

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

 其他

 

问题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)插入删除(排序的时候,比参考点小,直接插入头节点前,否则插入尾节点后)。

posted @ 2016-05-02 16:25  我在地狱  阅读(262)  评论(0编辑  收藏  举报