单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
单链表结构如下:
typedef int DataType;
typedef struct Node
{
struct Node* next; //指向下一个节点的指针
DataType data; //当前节点存放的数据
}Node,*pLinkNode;
注意:
Node* plist;
pLinkNode pplist;
①pLinkNode和Node是不同名字的同一个指针类型(命名的不同是为了概念上更明确)
②*pLinkNode类型的指针变量pplist表示它是单链表的头指针
③Node类型的指针变量plist表示它是指向某一结点的指针
单链表的一些基本操作实现如下:
void InitList(pLinkNode* pplist)
{
assert(pplist);
*pplist = 0; //初始化为空指针
}
void PrintList(pLinkNode pplist)
{
assert(pplist);
pLinkNode begin = pplist;
printf("List->");
while (begin)
{
printf("%d->", begin->data);
begin = begin->next;
}
printf("NULL\n");
}
pLinkNode GreateNode(DataType data)
{
pLinkNode newplist = (pLinkNode)malloc(sizeof(Node));
newplist->data = data;
newplist->next = NULL;
return newplist;
}
void PushBack(pLinkNode* pplist, DataType data)
{
assert(pplist);
if (*pplist == NULL)
{
*pplist = GreateNode(data);
}
else
{
pLinkNode end = *pplist;
while (end->next != NULL)
{
end = end->next;
}
end->next = GreateNode(data);
}
}
void PopBack(pLinkNode* pplist)
{
assert(pplist);
if (*pplist == NULL)
{
perror("error:");
return;
}
else
{
pLinkNode prev, end;
prev = *pplist;
end = *pplist;
while (end->next != NULL)
{
prev = end;
end = end->next;
}
if (end == (*pplist))
{
*pplist = NULL;
}
else
{
prev->next = NULL;
}
free(end);
}
}
void PushFront(pLinkNode* pplist, DataType data)
{
assert(pplist);
if (*pplist == NULL)
{
*pplist = GreateNode(data);
}
else
{
pLinkNode ret = GreateNode(data);
ret->next = *pplist;
*pplist = ret;
}
}
void PopFront(pLinkNode* pplist)
{
assert(pplist);
if (*pplist == NULL)
{
perror("error:");
return;
}
else
{
pLinkNode begin = *pplist;
if ((*pplist)->next == NULL)
{
*pplist = NULL;
}
else
{
*pplist = (*pplist)->next;
}
free(begin);
}
}
void GetListLength(pLinkNode plist)
{
assert(plist);
int count = 0;
pLinkNode begin = plist;
while (begin)
{
count++;
begin = begin->next;
}
printf("ListLength Is %d\n", count);
}
pLinkNode Find(pLinkNode plist, DataType data)
{
assert(plist);
pLinkNode begin = plist;
while (begin)
{
if (begin->data == data)
{
return begin;
}
begin = begin->next;
}
return NULL;
}
void Insert(pLinkNode* pplist, pLinkNode n,DataType data)//n是在主函数内用Find查找
{ //在节点n后面插入一个数据
assert(pplist);
if (*pplist == NULL || n == NULL)
{
perror("error:");
return;
}
pLinkNode ret = GreateNode(data);
ret->next = n->next;
n->next = ret;
}
void Remove(pLinkNode* pplist, pLinkNode n)//删除节点n
{
assert(pplist);
if (*pplist == NULL || n == NULL)
{
perror("error:");
return;
}
if (n == *pplist)
{
*pplist = (*pplist)->next; //包括只有一个节点的情况
free(n);
return;
}
pLinkNode prev, ret;
prev = *pplist;
ret = *pplist;
while (ret->next != NULL)
{
prev = ret;
ret = ret->next;
if (ret == n)
{
prev->next = ret->next;
free(n);
return;
}
}
}
void Erase(pLinkNode* pplist, DataType data, int flag)
{
assert(pplist);
if (*pplist == NULL)
{
perror("error:");
return;
}
pLinkNode ret;
do
{
ret = Find(*pplist, data);
if (ret != NULL)
{
Remove(pplist, ret);
}
} while (flag != 0 && ret);
}
常见的单链表面试题如下:
void PrintBack(pLinkNode plist) //从尾到头打印单链表
{
assert(plist);
if (plist->next != NULL)
{
PrintBack(plist->next); //递归调用
}
printf("%d->", plist->data);
}
void Del_MidNode(pLinkNode n) //删除一个无头的非尾结点a
{
if (n == NULL)
{
printf("Invaid n\n");
return;
}
pLinkNode ret = n->next;
n->data = ret->data;
n->next = ret->next;
free(ret);
}
void PushNode(pLinkNode n, DataType data)//在无头单链表的一个非头节点前插入一个节点
{
if (n == NULL)
{
printf("Invaid n\n");
return;
}
pLinkNode ret = GreateNode(n->data);
pLinkNode tmp = n->next;
n->data = data;
ret->next = tmp;
n->next = ret;
}
void JosephCycle(pLinkNode plist, int Cycle) //单链表实现的瑟夫环
{
assert(plist);
pLinkNode begin = plist;
int k = Cycle;
while (begin->next != begin)
{
int count = 1;
while (count++ != k)
{
begin = begin->next;
}
printf("del :%d->",begin->data);
pLinkNode del = begin->next;
begin->data = del->data;
begin->next = del->next;
}
}
void Reverse(pLinkNode* pplist) //逆置(翻转单链表)
{
assert(pplist);
if (*pplist == NULL)
{
perror("error:");
return;
}
pLinkNode begin = (*pplist)->next;
(*pplist)->next = NULL;
while (begin)
{
pLinkNode ret = begin;
begin = begin->next;
ret->next = *pplist;
*pplist = ret;
}
}
void BubbSort(pLinkNode* pplist) //冒泡排序
{
assert(pplist);
if (*pplist == NULL || (*pplist)->next == NULL)
{
return;
}
pLinkNode prev, tmp, end;
end = NULL;
while (end != *pplist)
{
prev = *pplist; //每次从头开始比较
tmp = (*pplist)->next;
while (tmp != end)
{
if (prev->data > tmp->data)
{
int ret = prev->data;
prev->data = tmp->data;
tmp->data = ret;
}
prev = prev->next;
tmp = tmp->next;
}
end = prev;
}
}
pLinkNode Merge(pLinkNode plist1, pLinkNode plist2)//合并两个有序单链表,合并后依然有序
{
if (plist1 == NULL)
{
return plist2;
}
if (plist2 == NULL)
{
return plist1;
}
if (plist1 == plist2)
{
return plist1;
}
pLinkNode plist,end;
if (plist1->data < plist2->data)
{
plist = plist1;
plist1 = plist1->next;
}
else
{
plist = plist2;
plist2 = plist2->next;
}
end = plist;
while (plist1 && plist2)
{
pLinkNode tmp;
if (plist1->data < plist2->data)
{
tmp = plist1;
plist1 = plist1->next;
}
else
{
tmp = plist2;
plist2 = plist2->next;
}
end->next = tmp;
end = tmp;
}
if (plist1)
{
end->next = plist1;
}
else if (plist2)
{
end->next = plist2;
}
return plist;
}
pLinkNode FindMidNode(pLinkNode plist)//查找单链表的中间节点,要求只能遍历一次链表。
{
assert(plist);
pLinkNode slow, fast;
int flag = 0;
slow = plist;
fast = plist;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
flag = 1;
if (fast == NULL) //双数的时候
{
return slow;
}
}
if (flag) //单数的时候
{
return slow;
}
return NULL;
}
总结:
单链表优点:
单链表中插入或者删除一个节点相对线性表比较高效,即找到链表表中第i-1个结点,然后修改其指向后继的指针,无需移动大量数据。
单链表缺点:
单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素,即不支持随机访问。