假如面试官让你十分钟完成双向循环链表

简介: 假如面试官让你十分钟完成双向循环链表

改进前

要是我问你会不会写双向循环链表,那你一定会不假思索的回答——我当然会。


但如果我让你十分钟之内完成它呢?


那你可能就会犹豫了,十分钟!?双向循环链表那么多的功能,怎么是10分钟能写完的东西呢?


如果你这样想了,那就请听我缓缓道来吧!


#define _CRT_SECURE_NO_WARNINGS
#include"List.h"
LTNode* BuyLTNode(LTDataType x)
{
  LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
  if (newnode == NULL)
  {
  perror("malloc fail");
  return NULL;
  }
  newnode->data = x;
  newnode->next = NULL;
  newnode->prev = NULL;
  return newnode;
}
LTNode* LTInit()
{
  LTNode* phead = BuyLTNode(-1);
  phead->next = phead;
  phead->prev = phead;
  return phead;
}
void LTPrint(LTNode* phead)
{
  assert(phead);
  printf("guard<==>");
  LTNode* cur = phead->next;
  while (cur != phead)
  {
  printf("%d<==>", cur->data);
  cur = cur->next;
  }
  printf("\n");
}
bool LTEmpty(LTNode* phead)
{
  assert(phead);
  return phead->next == phead;
}
void LTPushBack(LTNode* phead, LTDataType x)
{
  assert(phead);
  LTNode* tail = phead->prev;
  LTNode* newnode = BuyLTNode(x);
  tail->next = newnode;
  newnode->prev = tail;
  newnode->next = phead;
  phead->prev = newnode;
}
void LTPushFront(LTNode* phead, LTDataType x)
{
  assert(phead);
  LTNode* newnode = BuyLTNode(x);
  LTNode* first = phead->next;
  phead->next = newnode;
  newnode->prev = phead;
  newnode->next = first;
  first->prev = newnode;
}
void LTPopBack(LTNode* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTErase(phead->prev);
}
void LTPopFront(LTNode* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTNode* next = phead->next;
  phead->next = next->next;
  next->next->prev = phead;
  free(next);
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
  assert(phead);
  LTNode* cur = phead->next;
  while (cur != phead)
  {
  if (cur->data == x)
  {
    return cur;
  }
  cur = cur->next;
  }
  return NULL;
}
// 在pos之前插入
void LTInsert(LTNode* pos, LTDataType x)
{
  assert(pos);
  LTNode* prev = pos->prev;
  LTNode* newnode = BuyLTNode(x);
  // prev newnode pos
  prev->next = newnode;
  newnode->prev = prev;
  newnode->next = pos;
  pos->prev = newnode;
}
// 删除pos位置的值
void LTErase(LTNode* pos)
{
  assert(pos);
  LTNode* posPrev = pos->prev;
  LTNode* posNext = pos->next;
  posPrev->next = posNext;
  posNext->prev = posPrev;
  free(pos);
}
void LTDestroy(LTNode* phead)
{
  assert(phead);
  LTNode* cur = phead->next;
  while (cur != phead)
  {
  LTNode* next = cur->next;
  free(cur);
  cur = next;
  }
  free(phead);
}


如图,我们第一时间想到的恐怕就是这样的写法,又臭又长。


面试中你如果打算这么写代码,那恐怕10分钟确实不太够。


简化冗杂的代码

为了尽可能地减少代码量,让我们能在10分钟内打出来,我们需要发掘其中可以简化的部分。


头插和尾插的代码可以直接用LTInsert函数来实现。


反正头插和尾插也不过是LTInsert函数在头部和尾部的实现而已。


紧接着就是头删和尾删,同理,它们也不过是LTErase函数在头部和尾部的实现而已。


实现之后大概就是这个样子


#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef struct Node
{
  int data;
  struct Node* next;
  struct Node* prev;
}Node;
Node* BuyListNode(int x);
Node* SLInit();
void LTPopFront(Node* phead);
void LTPushFront(Node* phead, int x);
void LTPopBack(Node* phead);
void LTDestroy(Node* phead);
void LTPushBack(Node* phead, int x);
void LTErase(Node* phead);
void LTInsert(Node* pos, int x);
int LTEmpty(Node* phead);
void Print(Node* phead);
Node* BuyListNode(int x)
{
  Node* newnode = (Node*)malloc(sizeof(Node));
  newnode->data = x;
  newnode->next = NULL;
  newnode->prev = NULL;
  return newnode;
}
Node* SLInit()
{
  Node* phead = BuyListNode(-1);
  phead->next = phead;
  phead->prev = phead;
  return phead;
}
void LTInsert(Node* pos, int x)
{
  assert(pos);
  Node* newnode = BuyListNode(x);
  Node* prev = pos->prev;
  newnode->next = prev->next;
  newnode->prev = prev;
  prev->next = newnode;
  pos->prev = newnode;
}
void LTPushFront(Node* phead, int x)
{
  assert(phead);
  LTInsert(phead->next, x);
}
void LTPushBack(Node* phead, int x)
{
  assert(phead);
  LTInsert(phead, x);
}
void LTPopFront(Node* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTErase(phead->prev);
}
void LTErase(Node* pos)
{
  assert(pos);
  Node* prev = pos->prev;
  Node* next = pos->next;
  prev->next = next;
  next->prev = prev;
}
void LTPopBack(Node* phead)
{
  assert(phead);
  assert(!LTEmpty(phead));
  LTErase(phead->prev);
}
void LTDestroy(Node* phead)
{
  assert(phead);
  Node* cur = phead->next;
  while (phead != cur)
  {
  Node* next = cur->next;
  free(cur);
  cur = next;
  }
  free(phead);
}
int LTEmpty(Node* phead)
{
  assert(phead);
  return phead == phead->next;
}
void Print(Node* phead)
{
  Node* cur = phead->next;
  while (cur != phead)
  {
  Node* next = cur->next;
  printf("%d<==>", cur->data);
  cur = next;
  }
  printf("\n");
}


这样的代码量,我勉强能在10分钟之内打完,大家就更不用说了,5分钟足矣。


只要大家勤加练习,让面试官目瞪口呆指日可待!



相关文章
|
4月前
面试题 02.04:分割链表
面试题 02.04:分割链表
37 0
|
7月前
【面试必刷TOP101】删除链表的倒数第n个节点 & 两个链表的第一个公共结点
【面试必刷TOP101】删除链表的倒数第n个节点 & 两个链表的第一个公共结点
25 0
|
7月前
|
测试技术
【面试必刷TOP101】合并k个已排序的链表 & 判断链表中是否有环
【面试必刷TOP101】合并k个已排序的链表 & 判断链表中是否有环
36 0
|
7月前
【面试必刷TOP101】反转链表 & 链表内指定区间反转
【面试必刷TOP101】反转链表 & 链表内指定区间反转
36 0
|
8月前
|
Java
面试题-手写一个单向链表
面试题-手写一个单向链表
42 0
|
4月前
|
算法 Java C++
数据结构与算法面试题:实现一个函数,判断一个链表是否为回文链表。(提示:反转后半部分链表比对前半部分)
数据结构与算法面试题:实现一个函数,判断一个链表是否为回文链表。(提示:反转后半部分链表比对前半部分)
21 0
|
5月前
|
算法 Java 程序员
【Java程序员面试专栏 数据结构篇】二 高频面试算法题:链表
【Java程序员面试专栏 数据结构篇】二 高频面试算法题:链表
136 0
|
5月前
剑指Offer LeetCode 面试题22. 链表中倒数第k个节点
剑指Offer LeetCode 面试题22. 链表中倒数第k个节点
22 0
|
5月前
剑指Offer LeetCode 面试题06. 从尾到头打印链表
剑指Offer LeetCode 面试题06. 从尾到头打印链表
14 0
|
5月前
剑指Offer 面试题06. 从尾到头打印链表
剑指Offer 面试题06. 从尾到头打印链表
21 0