单链表常考算法题汇总

目录

1、从尾到头打印单链表

2、单链表实现约瑟夫环---时复=O(n),空复=O(1)

3、逆置/反转单链表---时间复杂度=O(n)

4、单链表排序(冒泡排序/快速排序)

(1)选择排序---时复=O(n^2),空复=O(1)

(2)冒泡排序---时复=O(n^2),空复=O(1)

(3)快速排序(亲测有效,成功运行)---时复=O(nlogn),空复=O(1)

5、k个节点为一组进行翻转

(1)反转单链表

(2)从头部开始组起的部分反转

(3)从尾部开始组起的部分反转

6、(查找/删除)链表中间节点(扩展:返回链表a/b节点)

(1)删除中间节点

(2)删除a/b节点

7、(查找/删除)链表的倒数第k个节点---时间复杂度=O(N),空间复杂度=O(1)

(1)查找单链表的倒数第k个节点

(2)删除单链表的倒数第k个节点

(3)删除双链表的倒数第k个节点

8、删除单链表的重复节点

(1)删除其它重复,只保留一个

(2)删除所有重复

9、删除单链表中指定值的节点

10、判断一个单链表是否有环,有环则求环大小和环入口节点

(1)判断是否有环:头节点开始,1快1慢,快2步,慢1步,快追上慢则有环

(2)环大小:(1)基础上,相遇节点开始,1个指针1步步走,直至再次回到该节点

(3)环入口节点:2种

法1:(2)基础上,头节点开始,1指针先走n步,2指针和1指针同时一步步走,直至相遇

法2:(1)基础上,快指针回到头节点,快慢指针同时一步步走,直至相遇

11、两链表相交

(1)判断1个链表是否有环,有环则返回第一个进入环的节点,无返回null

(2)判断2个无环链表是否相交,相交则返回第一个相交节点,不相交则返回null

(3)判断2个有环链表是否相交,相交则返回第一个相交节点,不相交则返回null

(4)判断两个(有环/无环)单链表是否相交?相交返回第一个相交点,不相交返回null

12、求两个已排序单链表中相同的数据

13、合并两个有序链表,合并后依然有序---O(n)


1、从尾到头打印单链表

方法1:递归
void printResverse2(ListNode* pHead) {
    if (pHead == NULL) return ;
    while (pHead->next != NULL) {
        printResverse2(pHead->next);
    }
    cout<<p->data<<' ';
}
//stack操作:push,pop,top,empty
//方法2:栈
void printResverse2(ListNode* pHead) {
    if (pHead == NULL) return ;
    ListNode * p = pHead;
    stack<ListNode *> stk;
    while(p != NULL) {
        stk.push(p);
        p = p->next;
    }
    while(!stk.empty()) {
        p = stk.top;
        stk.pop;
        cout<<p->data<<' ';
    }
}

2、单链表实现约瑟夫环---时复=O(n),空复=O(1)

暴力数数的方式时间复杂度=O(n*m),从1开始报数,报到m就杀死,下一个数从1开始编号,继续报数。
n个数最后只活了1个,n-1个节点被杀死,每一个被杀死的数都报数到m,所以计算了(n-1)*m次,约等于n*m

优化方法:
(1)取余函数(剃刀函数,见图a):y=x%i

(2)报数x与编号y的关系(见图b):y=(x-1)%i+1
假设环中有i个节点,报数不断增大,但环中节点个数有限。当环中有3个节点,报数到5就死(环大小<报数),当报到4时,编号回到环起点1。相当于取余函数,右移1个,再上移一个,即:y=(x-1)%i+1

报数 1 2 ... i i+1 i+2
编号 1 2 ... i 1 2

(3)新编号x与旧编号y的关系(见图c):y=(x-1+s)%i+1
最后1个活下来的节点的编号=1,那么可以反推2个节点活下来时该节点编号,3个活下来....n个活下来...
假如,环节点数=8,报到3就死。相当于(2)左移s个,即:y=(x-1+s)%i+1
旧编号:1,2,3,4,5,6,7,8
新编号:6,7,-,1,2,3,4,5
相当于:

旧编号(i个) 1 2 ... s-1 s s+1 ... i
新编号(i-1个) ... ... i-2 i-1 - 1 2 ...

(4)旧编号=(新编号+(m-1))%i+1
A: 编号=(报数-1)%i+1
B: 旧编号=(新编号+s-1)%i+1
C: s=(m-1)%i+1
其中,s是被干掉的编号,因为报数到m就死,所以得出的C式。
将C式代入B式,旧编号=(新编号+(m-1)%i)%i+1,中间的%i可以化解掉(具体就不关心啦)
最终,旧编号=(新编号+(m-1))%i+1

public static Node josephusKill(Node head, int m) {
		if (head == null || head.next == head || m < 1) {
			return head;
		}
		Node cur = head.next;
		int tmp = 1;//tmp为环的长度
		while (cur != head) {
			tmp++;
			cur = cur.next;
		}
		tmp = getLive(tmp, m);
		while (--tmp != 0) {//从1走到活着的tmp,走tmp-1步骤
			head = head.next;
		}
		head.next = head;//自己指向自己的环形单链表
		return head;
	}

    //获取活着的旧编号,i=旧环的大小,m是从1报数到m就死,

getLive(i-1,m)是新编号
    public static int getLive(int i, int m) {
        if (i == 1) {
            return 1;
        }
        return (getLive(i - 1, m) + m - 1) % i + 1;
    }

    public static int getLive(int i, int m) {
        if (i == 1) {
            return 1;
        }
        int last = 1;
        for (int curLen=2; curLen<=n; curLen++) {//2-n共n-1次循环
            last = (last + m-1)%curLen + 1;
        }
        return last;
    }

3、逆置/反转单链表---时间复杂度=O(n)

详见4(1)

4、单链表排序(冒泡排序/快速排序)

(1)选择排序---时复=O(n^2),空复=O(1)


(2)冒泡排序---时复=O(n^2),空复=O(1)

选择排序

public static Node selectionSort(Node head) {
    Node tail = null; // sorted part tail
    Node cur = head; // unsorted part head
    Node smallPre = null; // previous node of the smallest node
    Node small = null; // smallest node
    while (cur != null) {
        small = cur;
        smallPre = getSmallestPreNode(cur);
        if (smallPre != null) {
            small = smallPre.next;
            smallPre.next = small.next;
        }
        cur = cur == small ? cur.next : cur;
        if (tail == null) {
            head = small;
        } else {
            tail.next = small;
        }
        tail = small;
    }
    return head;
}

冒泡排序

void BubbleSord(pList plist) {
    pNode pCur = NULL;
    pNode pPre = NULL;
    pNode pTail = NULL;//pTail的指向是这个算法的关键
    if (plist == NULL || plist->next == NULL) {//排除空和一个结点的情况
        return;
    }
    while (plist != pTail) {//趟数
        int IsChange = 0;//排除排序时已经是有序的,则不需要再排序
        pPre = plist;
        pCur = pPre->next;
        while (pCur != pTail) {//次数
            if (pPre->data > pCur->data) {//升序
                int tmp = pPre->data;
                pCur->data = pPre->data;
                pPre->data = tmp;
                IsChange = 1;
            }
            pPre = pPre->next;
            pCur = pCur->next;
        }
        if (!IsChange) {//如果有序了,就不排了
            return;
        }
        pTail = pPre;
    }
}

(3)快速排序(亲测有效,成功运行)---时复=O(nlogn),空复=O(1)

思路:需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次支点的寻找。

注意:这里的GetPartition方法里判断条件:if(j->data < key)时,先i++,再swap(i->data, j->data)。因为i前(包含i)的数据都比key小;i后j前的数据都比key大。如果先swap再i++的话,很有可能把i的数据(<=key)换到j位置了。

完整代码如下:

#include <iostream>
using namespace std;

struct ListNode {
	int data;
	ListNode * next;
	ListNode(int _data = -1) : data(_data), next(NULL) {}
};//最后的分号不能丢

void swap(int & p, int & q) {//记得用&
	int tmp = p;
	p = q;
	q = tmp;
}

ListNode * createList(int a[], int n) {//用数组值创建单链表
    ListNode * pHead,* p;
    pHead = p = NULL;
    for (int i = 0; i < n; i++) {
        ListNode * tmp = new ListNode(a[i]);
        if (i == 0) pHead = tmp;
        else p->next = tmp;
        p = tmp;
    }
    return pHead;
}

ListNode * GetPartion(ListNode * pBegin, ListNode * pEnd)
{
	int key = pBegin->data;
	ListNode * i = pBegin;
	ListNode * j = i->next;
	while (j != pEnd)
	{
		if (j->data < key) {
		    i = i->next;
		    swap(i->data, j->data);
		}
		j = j->next;
	}
	swap(i->data, pBegin->data);
	return i;
}

void QuickSort(ListNode * pBeign, ListNode * pEnd)
{
	if (pBeign != pEnd) {
		ListNode * partion = GetPartion(pBeign, pEnd);
		QuickSort(pBeign, partion);
		QuickSort(partion->next, pEnd);
	}
}

int main() {
	int datalist[8] = { 4,2,5,3,7,9,0,1 };
	ListNode * pHead = createList(datalist, 8);
	QuickSort(pHead, NULL);
	ListNode * tmp = pHead;
	while (tmp != NULL) {
		cout << tmp->data << ' ';
		tmp = tmp->next;
	}
	return 0;
}

5、k个节点为一组进行翻转

(1)反转单链表

                               A

                                 B

                                        C

假设方法 reverse() 的功能是将单链表进行逆转。采用递归的方法时,我们可以不断着对子链表进行递归。我们对子链表 2->3->4 进行递归,即Node newList = reverse(head.next)。递归之后的结果如图B,逆转之后子链表 2->3->变为了 4->3->2。注意,刚才假设 reverse() 的功能就是对链表进行逆转。不过此时结点 1 仍然是指向结点 2 的。这个时候,我们再把结点1 和 2逆转一下,然后 1 的下一个结点指向 null 就可以了。如图C。递归的结束条件就是:当子链表只有一个结点,或者为 null 时,递归结束。

//逆序单链表
private static ListNode reverse(ListNode head) {
    if(head == null || head.next == null)
        return head;
    ListNode result = reverse(head.next);
    head.next.next = head;
    head.next = null;
    return result;
}

(2)从头部开始组起的部分反转

A

B

C

D

E

F

对于上面的这个单链表(见图A),其中 K = 3。我们把前K个节点与后面的节点分割出来(见图B和C),temp指向的剩余的链表,可以说是原问题的一个子问题。我们可以调用reverseKNode()方法将temp指向的链表每K个节点之间进行逆序。再调用reverse()方法把head指向的那3个节点进行逆序(见图D和E),接着,我们只需要把这两部分给连接起来就可以了(见图F)。

//k个为一组逆序
public ListNode reverseKGroup(ListNode head, int k) {
    ListNode temp = head;
    for (int i = 1; i < k && temp != null; i++) {
        temp = temp.next;
    }
    //判断节点的数量是否能够凑成一组
    if(temp == null)
        return head;

    ListNode t2 = temp.next;
    temp.next = null;
    //把当前的组进行逆序
    ListNode newHead = reverse(head);
    //把之后的节点进行分组逆序
    ListNode newTemp = reverseKGroup(t2, k);
    // 把两部分连接起来
    head.next = newTemp;
    
    return newHead;
}

(3)从尾部开始组起的部分反转

A

B

C

D

对于K = 3链表(见图A),我们把它从尾部开始组起,每 K 个节点为一组进行逆序。先进行逆序(见图B),逆序之后就可以把问题转化为从头部开始组起,每 K 个节点为一组进行逆序(见图C)。接再把结果逆序一次(见图D)。

public ListNode solve(ListNode head, int k) {
    head = reverse(head);//调用逆序函数
    // 调用每k个为一组的逆序函数(从头部开始组起)
    head = reverseKGroup(head, k);
    head = reverse(head);//再次逆序
    return head;
}

6、(查找/删除)链表中间节点(扩展:返回链表a/b节点)

                    图A

                              图B

(1)删除中间节点

len=0/1---不删除
len=2-----删第1个
len=3/4---删第2个
len=5/6---删第3个
用2个指针,pre和cur,初始分别为第1个和第3个。pre每次走1个,cur每次走2个,走不动了,删除pre+1。详见图A

(2)删除a/b节点

r=(a*n)/b,向上取整
a<1 或 a>b,直接返回。
r=1,删除头节点=返回head->next
r>1,如r=5,走r-2步。详见图B

(1)删除中间节点

public static Node removeMidNode(Node head) {
        if (head == null || head.next == null) {
            return head;
        }
        if (head.next.next == null) {
            return head.next;
        }
        Node pre = head;
        Node cur = head.next.next;
        while (cur.next != null && cur.next.next != null) {
            pre = pre.next;
            cur = cur.next.next;
        }
        pre.next = pre.next.next;
        return head;
    }

(2)删除a/b节点

    public static Node removeByRatio(Node head, int a, int b) {
        if (a < 1 || a > b) {
            return head;
        }
        int n = 0;
        Node cur = head;
        while (cur != null) {
            n++;
            cur = cur.next;
        }
        n = (int) Math.ceil(((double) (a * n)) / (double) b);
        if (n == 1) {
            head = head.next;
        }
        if (n > 1) {
            cur = head;
            while (--n != 1) {
                cur = cur.next;
            }
            cur.next = cur.next.next;
        }
        return head;
    }

7、(查找/删除)链表的倒数第k个节点---时间复杂度=O(N),空间复杂度=O(1)

(1)查找单链表的倒数第k个节点

思路:如果链表为空,或者k<链表长度,直接返回null。
设置两个指针A和B,相差k-1步,A先走k-1步骤,然后A和B一起走,当A走到最后,B即为所求。

(2)删除单链表的倒数第k个节点

思路:链表为空或k<1,直接返回。其他:从头走到尾,每走一步k-1(头部开始k-1),如果走到尾k=0,说明倒数第k个节点即为头节点,如果k<0,说明倒数第k个节点在链表中间,需要找到该节点的前一个节点:再次从头开始,每走一步k+1(头部开始k+1),直到k=0走到的节点即为倒数第k个节点的前一个节点

A -> B -> C -> D,k=2 A B C D
step1: 1 0 -1 -2
step2: -1 0    

(3)删除双链表的倒数第k个节点

与(2)相同,只不过需要注意指针

(1)查找单链表的倒数第k个节点

ListNode * findKthFromTail(ListNode * head, int k) {
    if (head == NULL || k < 1) {
        return NULL;
    }
    ListNode * pQuick = head, 
    ListNode * pSlow = NULL;
    for (int i = 0; i< k-1; i++) {
        if (pQuick->next == NULL) {//k>链表长度
            return NULL;
        }
        pQuick = pQuick->next;
    }
    pSlow = head;
    while (pQuick->next != NULL) {
        pQuick = pQuick->next;
        pSlow = pSlow->next;
    }
    return pSlow;
}

(2)删除单链表的倒数第k个节点

ListNode * removeLastKthNode(ListNode * head, int lastKth) {
    if (head == null || lastKth < 1) {
        return head;
    }
    ListNode * cur = head;
    while (cur != null) {
        lastKth--;
        cur = cur.next;
    }
    if (lastKth == 0) {
        head = head.next;
    }
    if (lastKth < 0) {
        cur = head;
        while (++lastKth != 0) {
            cur = cur.next;
        }
        cur.next = cur.next.next;
    }
    return head;
}

(3)删除双链表的倒数第k个节点

ListNode * removeLastKthNode(ListNode * head, int lastKth) {
    if (head == null || lastKth < 1) {
        return head;
    }
    ListNode * cur = head;
    while (cur != null) {
        lastKth--;
        cur = cur.next;
    }
    if (lastKth == 0) {
        head = head.next;
        head.last = null;
    }
    if (lastKth < 0) {
        cur = head;
        while (++lastKth != 0) {
            cur = cur.next;
        }
        ListNode * newNext = cur.next.next;
        cur.next = newNext;
        if (newNext != null) {
            newNext.last = cur;
        }
    }
    return head;
}

8、删除单链表的重复节点

(1)删除其它重复,只保留一个

(2)删除所有重复

/*(1)删除其它重复,只保留一个

Input: 1->1->2
Output: 1->2 */

ListNode* deleteOtherDuplicates(ListNode* head) {
    ListNode *pre = head, *cur = head;
    while (cur) {
        if (pre->val != cur->val) {
            pre->next = cur;
            pre = pre->next;
        }
        cur = cur->next;
    }
    if (pre) pre->next = nullptr;
    return head;
}

/*(2)删除所有重复

Input: 1->2->3->3->4->4->5
Output: 1->2->5 */

ListNode* deleteAllDuplicates(ListNode* head) {
    ListNode *dummy = new ListNode(-1);
    dummy->next = head;
    ListNode *pre = dummy, *cur = head;
    while (cur) {
        while (cur->next && cur->next->val == cur->val)
            cur = cur->next;
        if (pre->next == cur)
            pre = cur;
        else
            pre->next = cur->next;
        cur = cur->next;
    }
    return dummy->next;    //不能直接返回 head,因为 head 有可能被删除
}

ListNode* deleteOtherDuplicates(ListNode* head) {
    ListNode *pre = head, *cur = head;
    while (cur) {
        if (pre->val != cur->val) {
            pre->next = cur;
            pre = pre->next;
        }
        cur = cur->next;
    }
    if (pre) pre->next = nullptr;
    return head;
}

ListNode* deleteAllDuplicates(ListNode* head) {
    ListNode *dummy = new ListNode(-1);
    dummy->next = head;
    ListNode *pre = dummy, *cur = head;
    while (cur) {
        while (cur->next && cur->next->val == cur->val)
            cur = cur->next;
        if (pre->next == cur)
            pre = cur;
        else
            pre->next = cur->next;
        cur = cur->next;
    }
    return dummy->next;//不能直接返回 head,因为 head 有可能被删除
}

9、删除单链表中指定值的节点

#include <iostream>
using namespace std;

class Node {
    public:
        Node(int data) {
            value = data;
            next = NULL;
        }
    public:
        int value;
        Node *next;
};//分号不能丢

Node* removeNode(Node *head,int num) {
    Node *cur = NULL;
    while(NULL != head) {
        if(num != head->value) break;
        cur = head;
        head = head->next;
        delete cur;
    }

    cur = head;
    Node *pre = head;
    while(NULL != cur) {
        if(num == cur->value) pre->next = cur->next,delete cur;
        else                  pre = cur;
        cur = pre->next;
    }
    return head;
}

void printList(Node *head) {
    while(NULL != head) {
        cout << head->value << " ";
        head = head->next;
    }
    cout << endl;
}

int main() {
    Node *head = NULL;
    Node *ptr = NULL;
    for(int i =1;i<7;i++) {//构造链表
        if(NULL == head) {
            head = new Node(i);
            ptr = head;
            continue;
        }
        ptr->next = new Node(i);
        ptr = ptr->next;
    }
    cout << "before remove:" << endl;
    printList(head);
    cout << "after remove:" << endl;
    head = removeNode(head,2);
    printList(head);
    return 0;
}
/*输出如下:
before remove:
1 2 3 4 5 6 
after remove:
1 3 4 5 6 
*/

10、判断一个单链表是否有环,有环则求环大小和环入口节点

(1)判断是否有环:头节点开始,1快1慢,快2步,慢1步,快追上慢则有环

ListNode* MeetingNode(ListNode* pHead)
{
    if(pHead == nullptr)
        return nullptr;

    ListNode* pSlow = pHead->m_pNext;
    if(pSlow == nullptr)
        return nullptr;

    ListNode* pFast = pSlow->m_pNext;
    while(pFast != nullptr && pSlow != nullptr)
    {
        if(pFast == pSlow)
            return pFast;

        pSlow = pSlow->m_pNext;

        pFast = pFast->m_pNext;
        if(pFast != nullptr)
            pFast = pFast->m_pNext;
    }

    return nullptr;
}


(2)环大小:(1)基础上,相遇节点开始,1个指针1步步走,直至再次回到该节点

int LenOfLoop(ListNode* pHead)
{
	ListNode* meetingNode = MeetingNode(pHead);
    if(meetingNode == nullptr) return nullptr;
    int nodesInLoop = 1;//环结点数
    ListNode* pNode1 = meetingNode;
    while(pNode1->m_pNext != meetingNode)
    {
        pNode1 = pNode1->m_pNext;
        ++nodesInLoop;
    }
    return nodesInLoop;
}

(3)环入口节点:2种

法1:(2)基础上,头节点开始,1指针先走n步,2指针和1指针同时一步步走,直至相遇

ListNode* getLoopNode(ListNode* pHead)
{
	int nodesInLoop = LenOfLoop(pHead);
    // 先移动pNode1,次数为环中结点的数目
    pNode1 = pHead;
    for(int i = 0; i < nodesInLoop; ++i)
        pNode1 = pNode1->m_pNext;

    // 再同时移动pNode1和pNode2
    ListNode* pNode2 = pHead;
    while(pNode1 != pNode2)
    {
        pNode1 = pNode1->m_pNext;
        pNode2 = pNode2->m_pNext;
    }

    return pNode1;
}

法2:(1)基础上,快指针回到头节点,快慢指针同时一步步走,直至相遇

ListNode* getLoopNode(ListNode* pHead)
{
	ListNode* meetingNode = MeetingNode(pHead);
	ListNode* p1,p2;
	p1 = head;
	p2 = meetingNode;
	while(p1 != p2) {
		p1 = p1->next;
		p2 = p2->next;
	}
    return p1;
}


11、两链表相交

(1)判断1个链表是否有环,有环则返回第一个进入环的节点,无返回null

详见10(1)(3)

public static Node getLoopNode(Node head) {
	if (head == null || head.next == null || head.next.next == null) {
		return null;
	}
	Node n1 = head.next; // n1 -> slow
	Node n2 = head.next.next; // n2 -> fast
	while (n1 != n2) {
		if (n2.next == null || n2.next.next == null) {
			return null;
		}
		n2 = n2.next.next;
		n1 = n1.next;
	}
	n2 = head; // n2 -> walk again from head
	while (n1 != n2) {
		n1 = n1.next;
		n2 = n2.next;
	}
	return n1;
}

(2)判断2个无环链表是否相交,相交则返回第一个相交节点,不相交则返回null

分别计算两个链表的长度len1,len2,还有链表尾节点end1,end2。若end1!=end2,说明不相交直接返回null。
若end1==end2,说明相交。求第一个交点:长链表先走abs(len1-len2)步,然后两个同时一步步走,直至相遇。

public static Node noLoop(Node head1, Node head2) {
	if (head1 == null || head2 == null) {
		return null;
	}
	Node cur1 = head1;
	Node cur2 = head2;
	int n = 0;
	while (cur1.next != null) {
		n++;
		cur1 = cur1.next;
	}
	while (cur2.next != null) {
		n--;
		cur2 = cur2.next;
	}
	if (cur1 != cur2) {
		return null;
	}
	cur1 = n > 0 ? head1 : head2;
	cur2 = cur1 == head1 ? head2 : head1;
	n = Math.abs(n);
	while (n != 0) {
		n--;
		cur1 = cur1.next;
	}
	while (cur1 != cur2) {
		cur1 = cur1.next;
		cur2 = cur2.next;
	}
	return cur1;
}

(3)判断2个有环链表是否相交,相交则返回第一个相交节点,不相交则返回null

                   图A

                        图B

                           图C

分别求两个链表的第一个入环节点loop1和loop2
若loop1==loop2(图A),直接返回第一次相交节点=loop1
若loop1!=loop2,判断是那种拓扑(图B还是图C)
链表1从loop1出发,走一圈还会再回到loop1,中间若没遇到loop2,则说明是不相交(图B)。若遇到loop2说明是相交(图C),
只不过loop1是离链表1近,loop2离链表2近,返回loop1或loop2都可以。

public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
	Node cur1 = null;
	Node cur2 = null;
	if (loop1 == loop2) {
		cur1 = head1;
		cur2 = head2;
		int n = 0;
		while (cur1 != loop1) {
			n++;
			cur1 = cur1.next;
		}
		while (cur2 != loop2) {
			n--;
			cur2 = cur2.next;
		}
		cur1 = n > 0 ? head1 : head2;
		cur2 = cur1 == head1 ? head2 : head1;
		n = Math.abs(n);
		while (n != 0) {
			n--;
			cur1 = cur1.next;
		}
		while (cur1 != cur2) {
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		return cur1;
	} else {
		cur1 = loop1.next;
		while (cur1 != loop1) {
			if (cur1 == loop2) {
				return loop1;
			}
			cur1 = cur1.next;
		}
		return null;
	}
}

(4)判断两个(有环/无环)单链表是否相交?相交返回第一个相交点,不相交返回null

public static Node getIntersectNode(Node head1, Node head2) {
	if (head1 == null || head2 == null) {
		return null;
	}
	Node loop1 = getLoopNode(head1);
	Node loop2 = getLoopNode(head2);
	if (loop1 == null && loop2 == null) {
		return noLoop(head1, head2);
	}
	if (loop1 != null && loop2 != null) {
		return bothLoop(head1, loop1, head2, loop2);
	}
	return null;
}

12、求两个已排序单链表中相同的数据

思路:分别创建两个结点变量cur1,cur2,如果cur1->data大于cur2->data,则cur2 = cur2->next;如果cur1->data小于cur2->data,则cur1 = cur1->next;如果cur1->data= cur2->data,则cur1和cue2 同时向后走

void commonNode(ListNode * List1, ListNode * List2)
{
	ListNode *cur1,*cur2;
	cur1 = List1, cur2  = List2;
	while (cur1 != NULL && cur2 != NULL)
	{
		if (cur1->data < cur2->data) {
			cur1 = cur1->Next;
		}
		else if (cur1->data > cur2->data) {
			cur2 = cur2->Next;
		} else {
			printf("  %d  ", cur1->data);
			cur1 = cur1->Next;
			cur2 = cur2->Next;
		}
	}
}

13、合并两个有序链表,合并后依然有序---O(n)

递归方式

ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
    if(pHead1 == nullptr)
        return pHead2;
    else if(pHead2 == nullptr)
        return pHead1;

    ListNode* pMergedHead = nullptr;

    if(pHead1->m_nValue < pHead2->m_nValue)
    {
        pMergedHead = pHead1;
        pMergedHead->m_pNext = Merge(pHead1->m_pNext, pHead2);
    }
    else
    {
        pMergedHead = pHead2;
        pMergedHead->m_pNext = Merge(pHead1, pHead2->m_pNext);
    }

    return pMergedHead;
}

非递归方式

ListNode * Merge(ListNode * pHead1, ListNode * pHead2) {
    ListNode * p1,p2,p,pMergeHead;
    p1 = pHead1; p2 = pHead2; pMergeHead = p = NULL;
    if (pHead1->data < pHead2->data) {
        pMergeHead = pHead1; p1 = p1->next;
    } else {
        pMergeHead = pHead2; p2 = p2->next;
    }
    p = pMergeHead;
    while (p1 && p2) {
        if (pHead1->data < pHead2->data) {
            p->next = p1; p1 = p1->next;
        } else {
            p->next = p2; p2 = p2->next;
        }
        p = p->next;
    }
    if (p1) p->next = p1;
    if (p2) p->next = p2;
}

猜你喜欢

转载自blog.csdn.net/wuhuagu_wuhuaguo/article/details/106354522