单链表基础题总结分析

3 篇文章 0 订阅

1.从尾到头打印单链表
2.在无头单链表的一个节点前插入一个节点
3.单链表实现约瑟夫环
4.逆置/反转单链表
5.单链表排序(冒泡排序&快速排序)
6.合并两个有序链表,合并后依然有序
7.查找单链表的中间节点,要求只能遍历一次链表
8.查找单链表的倒数第k个节点,要求只能遍历一次链表



1.分析
先打印1的子链表再打1,2.3.4同1(递归)

void PrintTailToHead(ListNode* plist)
{
   if(plist==NULL)
   return;
   PrintTailToHead)(plist->next);
   printf("%d->",plist->data);
}


//测试
void TestList3()
{
    ListNode* List=NULL;
    pushback(&List,1);
    pushback(&List,2);
    pushback(&List,3);
    pushback(&List,4);
    PrintList(list);
    PrintTailToHead(list);
}

2.分析
(1)例如单链表1->2->4->5->,在4节点之前插入一个3节点,只能在节点4后插入,然后和节点4进行交换
(2)1->2->4->,在4节点之前插入一个3节点,用指针来确定位置

void InsertNonHead(ListNode* pos,DataType x)
{
   assert(pos);
   ListNode* tmp = BuyNode(x);
   ListNode* next = pos->next;
   pos->next = tmp;
   tmp->next = next;
   //插入值
   DataType tmpData = pos->data;
   pos->data = tmp->data;
   tmp->data = tmpData;
   //交换值
}

3.分析
*约瑟夫环:一圈共有N个人,开始报数,报到M的人自杀,然后重新开始报数,问最后自杀的人是谁?
有N个数,删除第K个数,看剩下的数是多少?
分析:方法一:数组
删除数据并前移余下的数,将删除的数据标记为-1,重新计数
方法二:节点
采用节点删除

ListNode*JosephRing(ListNode* List)
{
    if(list == NULL)
    //断言:一定不可为空;if:可以为空,用条件判断
    return NULL;
    ListNode* cur = list;
    while(cur->next != cur)
    {
      int count = k;
      while(--count)
      //--count:走k-1次;count--:走k次
      {
         cur = cur->next;
      }
      ListNode* next = cur->next;
      cur->next = next->data;
      cur->next = next->next;
      free(next);
    }
}


//
void TestList4()
{
    ListNode* List=NULL;
    pushback(&List,1);
    pushback(&List,2);
    pushback(&List,3);
    pushback(&List,4);
    PrintList(list);
}


    ListNode* pos = Find(list,4);//变成环
    pos->next = list;
    ListNode* last = JosephRing(list,3);
    printf("幸存者:%d\n",last->data);
    //解环,置空
    free(last);
    list = last = NULL;

4.分析
采用头插的方法

ListNode* Reverse(ListNode* list)
{
   ListNode* newlist = NULL;
   ListNode* cur = list;
   //当cur为空时则证明全部逆置结束
   while(cur)
   {
      ListNode* tmp = cur;
      cur = cur->next;//摘节点
      tmp->next = newlist;
      newlist = tmp;//插节点
   }
   return newlist;
}

5.分析:
a.next=NULL
b.使用tail指针控制终止位置:next=tail

void BubbleSort(ListNode* list)
{
   if(list == NULL || list->next == NULL)
   {
     return;
   }
 ListNode* tail = NULL;
 while(tail!=list->next)
 int exchange = 0;
 {
   ListNode* cur = list;
   ListNode* next = cur->next;
   while(next!=tail)
   {
      if(cur->data > next->data)
      {
         DataType tmp = cur->data;
         cur->data = next->data;
         next->data = tmp;
      }
      cur = cur->next;
      next = next->next;
   }
   if(exchange == 0)
   {
      break;
   }
   tail = cur;
 }
}

6.分析:
第一个数头插,其余尾插

ListNode* Merge(ListNode* list1,ListNode* list2)
{
   if(list1 == NULL)
   {
      return list2;
   }
   if(list2 == NULL)
   {
      return list1;
   }
   //先摘一个节点做头

   ListNode* list = NULL;
   if(list->data < list1->data)
   //判断链表1和链表2中头小的那个,默认为2比1小
   {
      list = list2;
      list2 = list2->next;
   }
   else
   {
      list = list1;
      list1 = list1->next;
   }
   //尾插   
   ListNode* tail = list;
   while(list1&&list2)
   {
      if(list1->data < list2->data)
      {
         tail->next = list1;
         list1 = list1->next;
      }
      else
      {
         tail->next = list2;
         list2 = list2->next;
      }
      tail = tail->next;
    }
    //
    if(list1)
      tail->next = list1;
    else
      tail->next = list2;
    return list;
}

7.分析:
采用快慢指针,中间节点有两种情况;如果是奇数个节点的话取中间节点;如果有偶数个节点则由奇数的结果决定。fast一次走两步,slow一次走一步当fast指向空时,此时slow指向中间节点。

ListNode* FindMidNode(ListNode* list)
{
   if(list == NULL)
   return NULL;
   ListNode* slow = list;
   ListNode* fast = list;
   while(fast&&fast->next)
   {
      slow = slow->next;
      fast = fast->next->next;
   }
   return slow;
}

8.分析:
fast先走k-1步后,(fast和slow相差k-1)fast和slow再同时走,fast走一步,slow走一步。当fast走向尾节点时,则slow指向倒数第k个;
fast先走k步后同上,当fast=NULL时,slow为倒数第k个

ListNode* FindTail_k_Node(ListNode* list,int K)
{
   ListNode* slow = list;
   ListNode* fast = list;
   while(k--)
   {
      return NULL;
      fast = fast->next;
   }
   while(fast)
   {
      slow = slow->next;
      fast = fast->next;
   }
   return slow;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值