链表问题

关于链表插入和删除的注意事项:
1.特殊处理链表为空和链表长度为1的情况。
2.注意插入操作调整的过程
3.注意头尾节点需要特殊考虑

给定一个整数num,在有序环形链表中插入一个节点值为num的节点,并且保证这个环形单链表依然有序。

采用两个节点指针,判断何种情况需要在两个指针之间插入节点。如果两个指针转了一圈都没有发现要插入的位置,则插在头结点前

给定一个链表的头结点head,在给定一个数num,把链表调整成节点值小于num的节点都放在链表值等于num的放在链表的中间,链表值大于num的节点放在链表的右边

方法一:
1.将链表的所有节点都放在数组中,然后将数组进行快排划分调整过程。
2.将数组重新连成链表

方法二:
分别将小于部分,等于部分,大于部分形成三个小链表,再将三个小链表连成大链表

给定两个有序链表的头结点,h1和h2打印两个有序链表的公共部分。

如有有一个为空,直接返回
否则,分别从两个链表的头结点遍历,如果n1

设计一个单链表函数,给定一个链表的头节点,使每k个节点之间逆序,如果最后不够k个节点,则不调整。

方法一:
利用栈进行处理,元素依次进栈,进够k个就依次弹出,如果最后不足k个则不要逆序
方法二:
记录下每组节点的头节点,每收集k个元素进行逆序调整,

给定一个单链表的头结点,再给定一个val,把所有等于val的节点删掉

可以看最构造新链表的过程。

一个链表中,每个节点不仅含有一条指向下一个节点额next指针,同时含有一条rand指针,rand指针可能指向任何一个链表中的节点,请复制这种含有rand指针节点的链表。

把每一个节点的拷贝节点放到原节点的后面。

1.单链表的创建、测长、节点查找、删除、插入、打印、反转

这里写图片描述

链表的反转
为了反转这个单链表,我们先让头结点的next域指向结点2,再让结点1的next域指向结点3,最后将结点2的next域指向结点1,就完成了第一次交换,顺序就变成了Header-结点2-结点1-结点3-结点4-NULL,然后进行相同的交换将结点3移动到结点2的前面,然后再将结点4移动到结点3的前面就完成了反转,思路有了,就该写代码了:


//将1,2节点交换,
//head ->next =  node2;
//node1 ->next = node2->next;
//node2 ->next = node1;

Node *Reverse_List(Node *head){
    Node *rev_head = NULL;
    Node *pNode = pHead;
    Node *pPrev = NULL;
    while(pNode != NULL){
        Node *pNext = pNode ->next;
        if(pNode)
            rev_head = pNode;
        pNode ->next = pPrev;
        pPrev = pNode;
        pNode = pNext;


    } 
    return rev_head;

}

2.双向链表的创建、测长、节点查找、删除、插入、打印、反转

3.不使用缓冲区移除链表中重复的节点

4.编写算法找出单链表中倒数第k个节点

利用快指针慢指针来实现:
两个指针指向头节点,快指针先向前走k-1步,然后两个指针再一起移动,最后快指针到达链表末尾的时候慢指针指向倒数第k个节点。

void FindKthtoTail(Node *head, int k ){
    if(NULL == head || 0 == k)
        return;
    Node * quick = head;
    Node* slow  =NULL;
    for(size_t  i = 0; i< k-1 ;++i){  //快指针先走k-1步
        if(quick ->next ){
            quick = quick->next ;
    }

    slow = head;
    while(quick ->next){  //快慢指针同时前进
        quick = quick-<next; 
        slow = slow->next;
   }

  cout<<slow->data<<endl;  
  return ;    
}

5.删除单链表中某个节点,且只能访问该节点

6.以给定值x为基准,将链表分割成两部分,所有小于x的节点排在x之前

7.两个链表表示两个整数,每个节点表示整数的一位,数位反向(正向)存放,以链表的形式返回两个数的和——大整数问题

8.编写一个方法,传入一个有环链表,返回环路的头结点。如果无环则返回NULL

利用hash表来实现,遍历每个节点,直到出现一个重复出现的节点
方法二:利用快指针、慢指针:若有环,则两个指针会在链表中的某个位置相遇,此时快指针从头重新遍历,当再次相遇的时候,就都指向环头。

9.编写一个方法,判断链表是否是回文串

10.寻找单链表中的中间元素

11.单链表的正向排序

12.判断链表是否存在环

13.有序单链表的合并

Node *Merge(Node *head1,Node *head2){
    if(head1 == NULL)
        return head2;
    else if(head2 == NULL)
        return head1;
    Node *merged_head = NULL;
    if(head1->data < head2->data){
        merged_head = head1;
        merged_head - >next  =Merge(head1->,head2)
    }
    else {
        merged_head = head2;
        merge_head ->next = Merge(head1,head2->next);
    }
    return merged_head;
}

14.约瑟夫环问题

15.有序双向循环链表的插入

16.删除两个双向循环链表的相同节点

17.反向打印链表

利用栈、递归来实现

void Reverse_PrintList(Node *head){

    stack<Node*> nodes;
    Node *pNode = head;
    while(pNode != NULL){
        nodes.push(pNode);
        pNode = pNode->next;
    }
    while(!nodes.empty()){
        pNode = nodes.top();
        nodes.pop();
        cout<< pNode -> data<<endl;
    }

}

//利用递归来实现
void reverse_PrintList(Node *head){
    if(head){
        reverse_PrintList(head->next);
        cout<<head->data<<endl;
    }
    return ;


}

18.单链表反转的递归实现

19.复杂链表的复制

20.求两个链表的第一个公共子节点

两个链表从后到前寻找,找到最后一个相同的节点就是两个链表的第一个公共子节点,使用两个辅助栈。
Tips:该题在逆时针旋转90度之后编程寻找最低公共祖先的问题。

21.二叉搜索树和双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表,不能创建任何新节点,只能调整树中节点指针的指向。

解法:中序遍历的过程中,将前驱和后继连接起来


void change(Node *p, Node *&last) //中序遍历
{
 if (!p)
  return;
 change(p->left, last);
 if (last)
  last->right = p;
 p->left = last;

 last = p;
 change(p->right, last);
}

void main()
{
 Node *root = create();
 Node *tail = NULL;
 change(root, tail);
 while (tail)
 {
  cout << tail->data << " ";
  tail = tail->left;
 }
 cout << endl;
}

22.圆圈中最后剩下的数字:0,1,…,n-1 这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字,求出这个圆圈里剩下的最后一个数字

给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。

如果不带环:

我们只要判断俩个链表的尾指针是否相等。
相等,则链表相交;否则,链表不相交。

1.先判断带不带环
2.如果都不带环,就判断尾节点是否相等
3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
如果在,则相交,如果不在,则不相交。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值