【数据结构】链表面试题

1、倒序打印链表

(1)非递归方式
在这里插入图片描述
代码如下:

void ReversePrint(ListNode **pFirst)
{
 ListNode *last = NULL;
 ListNode *cur = NULL;
 assert(*pFirst != NULL);
 while(last != *pFirst)
 {
  cur = *pFirst;
  while(cur != NULL)
  {
   if(cur->next == last)
   {
    printf("%d ",cur->data);
    last = cur;
   }
   cur = cur->next;
  }
 }
 printf("\n");
}

(2)递归方式
可以在递归的最后一层(即最后一次递归调用)时打印最后一个结点的元素,在每次函数调用结束返回时打印当前结点的元素。代码如下:

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

2、逆置链表

在这里插入图片描述
代码如下:

ListNode *ReverseList(ListNode **pFirst)
{
 ListNode *tmp = NULL;
 ListNode *pre = NULL;
 ListNode *cur = NULL;
 ListNode *result = NULL;
 assert(*pFirst != NULL);
 cur = *pFirst;
 while(cur != NULL)
 {
  tmp = cur->next;
  if(cur->next == NULL)
  {
   result = cur;
  }
  cur->next = pre;
  pre = cur;
  cur = tmp;
 }
 return result;
}

3、删除一个无头链表的非尾结点

在这里插入图片描述
代码如下:

void RemoveNodeNotTail(ListNode *pos)
{
 if(pos == NULL)
 {
  return ;
 }
 pos->data = pos->next->data;
 pos->next = pos->next->next;
}

4、在无头链表前插入一个结点

在这里插入图片描述
代码如下:

void InsertNoHead(ListNode *pos, int data)
{
 ListNode *NewNode = NULL;
 if(pos == NULL)
 {
  return ;
 }
 NewNode = CreateNode(data);
 NewNode->data = pos->data;
 NewNode->next = pos->next;
 pos->data = data;
 pos->next = NewNode;
}

5、单链表实现约瑟夫环

整体思路分为两步走:
(1)先使链表构成一个环(最后一个结点的next等于第一个结点);
(2)如果链表中的剩余结点超过一个,每次找到第k个结点,删除它。
代码如下:

ListNode *JocephCircle(ListNode *pFirst, int k)
{
 ListNode *result = NULL;
 ListNode *pre = NULL;
 ListNode *cur = NULL;
 int i = 0;
 assert(pFirst != NULL);
 cur = pFirst;
 //先使链表构成一个环(最后一个结点的next等于第一个结点)
 while(cur->next != NULL)
 {
  cur = cur->next;
 }
 cur->next = pFirst;
 //如果链表中剩余结点超过一个,每次找到第k个结点,删除它
 cur = pFirst;
 while(cur->next != cur)
 {
  for(i=0; i<k-1; i++)
  {
   pre = cur;
   cur = cur->next;
  }
  //删除元素
  pre->next = cur->next;
  //free(cur);
  cur = pre->next;
 }
 result = cur;
 result->next = NULL;
 return result;
}

6、冒泡排序

在这里插入图片描述
代码如下:

void BubbleSort(ListNode **pFirst)
{
 ListNode *cur = NULL;
 ListNode *last = NULL;
 ListNode *pre = NULL;
 DataType tmp = 0;
 DataType max = 0;
 assert(*pFirst != NULL);
 while(last != (*pFirst)->next)
 {
  cur = (*pFirst)->next;
  max = (*pFirst)->data;
  while(cur != last)
  {
   if(cur->data>max) //当前值大于最大值时,交换两数
   {
    tmp = max;
    max = cur->data;
    cur->data = tmp;
   }
   pre = cur;
   cur = cur->next;
  }
  //一次循环结束后,把最大值放入使循环结束的结点中,把该结点中的值放入链表开头
  tmp = pre->data;
  pre->data = max;
  (*pFirst)->data = tmp;
  last = pre;
 }
}

7、合并两个有序链表

整体思路如下:
用result记录新链表,两个链表的当前数进行比较,哪个小,就先放入链表中,并且向后移动。直至两个链表的最后一个结点,结束循环。代码如下:

ListNode *MergeOrderedList(ListNode *p1First, ListNode *p2First)
{
 ListNode *cur1 = NULL;
 ListNode *cur2 = NULL;
 ListNode *result = NULL;
 ListNode *tail = NULL;
 ListNode *node = NULL;
 assert(p1First);
 assert(p2First);
 cur1 = p1First;
 cur2 = p2First;
 while((cur1 != NULL)&&(cur2 != NULL))
 {
  if(cur1->data<=cur2->data)
  {
   node = cur1;
   cur1 = cur1->next;
   if(tail == NULL)
   {
    result = node;
   }
   else
   {
    tail->next = node;
   }
   node->next = NULL;
   tail = node;
  }
  else
  {
   node = cur2;
   cur2 = cur2->next;
   if(tail == NULL)
   {
    result = node;
   }
   else
   {
    tail->next = node;
   }
   node->next = NULL;
   tail = node;
  }
 }
 if(cur1 != NULL)
 {
  tail->next = cur1;
 }
 if(cur2 != NULL)
 {
  tail->next = cur2;
 }
 return result;
}

8、查找链表的中间结点(只能遍历一次链表)

思路:
取两个指针走;
一个快指针,一个慢指针;
快指针走两步,慢指针走一步;
直至快指针走到链表末尾,结束循环;
慢指针所在位置就是链表的中间结点。
代码如下:

ListNode *FindMid(ListNode *pFirst)
{
 ListNode *cur = NULL;
 ListNode *mid = NULL;
 int count = 0;
 assert(pFirst != NULL);
 cur = pFirst;
 mid = pFirst;
 while(cur != NULL)
 {
  cur = cur->next;
  count++;
  if((count%2)==0)
  {
   mid = mid->next;
   count = 0;
  }
  //cur = cur->next;
  //count++;
 }
 return mid;
}

9、查找链表的倒数第k个结点(只能遍历一次链表)

思路:
取快、慢两个指针走;
快指针先走k步;
然后在快、慢指针一起走;
直至快指针走到链表末尾,结束循环;
慢指针所在位置即为链表的倒数第k个结点。
代码如下:

ListNode *FindK(ListNode *pFirst, int k)
{
 ListNode *fast = NULL;
 ListNode *slow = NULL;
 assert(pFirst != NULL);
 fast = pFirst;
 slow = pFirst;
 while(k)
 {
  fast = fast->next;
  k--;
 }
 while(fast != NULL)
 {
  fast = fast->next;
  slow = slow->next;
 }
 return slow;
}

10、删除链表的倒数第k个结点(只能遍历一遍链表,不能使用替换法删除)

思路:
用快、慢两个指针走;
快指针先走k+1步;
再快、慢指针一起走;
直至快指针走到链表末尾,结束循环;
找到倒数第k+1个结点,让第k+1个结点指向第k个结点之后的结点,即删除第k个结点。
代码如下:

void RemoveK(ListNode **pFirst, int k)
{
 ListNode *del = NULL;
 ListNode *fast = NULL;
 ListNode *slow = NULL;
 assert(*pFirst != NULL);
 fast = *pFirst;
 slow = *pFirst;
 while(k+1)
 {
  fast = fast->next;
  k--;
 }
 while(fast != NULL)
 {
  fast = fast->next;
  slow = slow->next;
 }
 del = slow->next;
 slow->next = slow->next->next;
 //free(del);
}

11、求两个已排序单链表中相同的数据,并用链表返回

思路:
两个链表中的当前数进行比较,哪个小,哪个就往前走,两个数相等时,就将其放入新链表中,直至循环结束。
代码如下:

ListNode *UnionSet(ListNode *list1, ListNode *list2)
{
 ListNode *cur1 = NULL;
 ListNode *cur2 = NULL;
 ListNode *result = NULL;
 ListNode *tail = NULL;
 ListNode *node = NULL;
 assert(list1 != NULL);
 assert(list2 != NULL);
 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
  {
   node = cur1;
   cur1 = cur1->next;
   cur2 = cur2->next;
   if(tail == NULL)
   {
    result = node;
   }
   else
   {
    tail->next = node;
   }
   node->next = NULL;
   tail = node;
  }
 }
 return result;
}

== 上述内容均为学习过程总结,如有不足之处,请指正 ==

猜你喜欢

转载自blog.csdn.net/cottonrose_orange/article/details/82784945