您的位置:首页 > 编程语言 > C语言/C++

C语言实现单链表的基本操作及其部分面试题

2016-03-28 18:07 621 查看
//单链表的基本数据类型及其结构

typedef int DataType;
typedef struct LinkNode
{
DataType data;
struct LinkNode *next;
}LinkNode,*pLinkNode,*pLinkList;

//单链表的初始化
void InitLinkList(pLinkList* pHead)//初始化
{
assert(pHead);
*pHead = NULL;
}

//当尾插,头插,插入时都需要建立一个新的结点,为方便建立一个创建结点的函数

pLinkNode BuyNode(DataType d)//创建一个结点
{
pLinkNode newNode = (pLinkNode)malloc(sizeof(LinkNode));
newNode->data = d;
newNode->next = NULL;
return newNode;
}

//单链表的销毁,即把单链表中所有的结点都释放掉

void Destory(pLinkList* pHead)//销毁
{
if(*pHead == NULL)
{
return;
}
else
{
pLinkNode cur = *pHead;
while (cur)
{
pLinkNode del = cur;
cur = cur->next;
free(del);
del = NULL;
}
}
}

//在当前单链表的末尾插入一个结点

void PushBack(pLinkList* pHead,DataType d)//尾插
{
pLinkNode cur = *pHead;
pLinkNode newNode = BuyNode(d);
assert(pHead);
if(cur == NULL)
{
*pHead = newNode;
return ;
}
while(cur->next)
{
cur = cur->next;
}
cur->next = newNode;
}

//把当前单链表的最后一个结点删除掉
void PopBack(pLinkList* pHead)//尾删
{
pLinkNode cur = *pHead;
assert(pHead);
if(*pHead == NULL)
{
return;
}
else if((*pHead)->next == NULL)
{
free(*pHead);
*pHead = NULL;
}
else
{
pLinkNode del;
while (cur->next->next)
{
cur = cur->next;
}
del = cur->next;
cur->next = NULL;
free(del);
del = NULL;
}
}

//在当前单链表的头部插入一个结点
void PushFront(pLinkList* pHead,DataType d)//头插
{
pLinkNode newNode = BuyNode(d);
pLinkNode cur = *pHead;
assert(pHead);
if(cur == NULL)
{
*pHead = newNode;
return;
}
else
{
newNode->next = *pHead;
*pHead = newNode;
}
}

//将单链表的第一个结点删除掉
void PopFront(pLinkNode* pHead)//头删
{
assert(pHead);
if(*pHead == NULL)
{
return;
}
else
{
pLinkNode del = *pHead;
*pHead = (*pHead)->next;
free(del);
del = NULL;
}
}

//获取单链表的长度,增加一个计数器,将单链表遍历一遍
int GetListLength(pLinkList* pHead)//求单链表的长度
{
pLinkNode cur = *pHead;
int count = 0;
assert(pHead);
while(cur)
{
count++;
cur = cur->next;
}
return count;
}

//给定单链表的一个结点,在该结点的位置插入一个新的节点,遍历单链表,只要(cur->next==pos),使新结点的next指向pos,再将新结点赋给cur->next。
void InsertList(pLinkList* pHead,pLinkNode pos,DataType d)//插入
{
pLinkNode newNode = BuyNode(d);
pLinkNode cur = *pHead;
assert(pHead);
assert(pos);
if(*pHead == pos)
{
newNode->next = *pHead;
*pHead = newNode;
}
else
{
while (cur->next != pos)
{
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
}
}

//遍历单链表,只要某结点的值与要找的值相等,则返回该结点,否则返回NULL
pLinkNode Find(pLinkList* pHead,DataType d)//查找

{
pLinkNode cur = *pHead;
assert(pHead);
while(cur)
{
if(cur->data == d)
{
return cur;
}
cur = cur->next;
}
return NULL;
}

//方法1 利用Find函数找到需要删除的结点pos,遍历单链表,只要(cur->next == pos),将pos->next赋给cur->next,再将pos释放掉。
void Remove(pLinkList* pHead,DataType d)//删除结点
{
pLinkNode pos = Find(pHead,d);
pLinkNode cur = *pHead;
pLinkNode del = NULL;
assert(pHead);
if(*pHead == pos)
{
del = *pHead;
*pHead = (*pHead)->next;
free(del);
del = NULL;
}
else
{
while (cur->next != pos)
{
cur = cur->next;
}
del = cur->next;
cur->next = del->next;
free(del);
}
}

//方法2 不需要已有函数Find,原理与方法1一样
void Remove(pLinkList* pHead,DataType d)//删除结点
{
pLinkNode cur = *pHead;
pLinkNode del = NULL;
pLinkNode prev = NULL;
assert(pHead);
if(cur == NULL)
{
return;
}
while(cur)
{
if(cur->data == d)
{
del = cur;
if(cur == *pHead)
{
*pHead = (*pHead)->next;
}
else
{
prev->next = cur->next;
}
free(del);
break;
}
prev = cur;
cur = cur->next;
}
}

//删除单链表中所有相同的结点,首先,遍历单链表,找到第一个要删除的结点,删除并释放掉,同时增加一个指向该结点下一个结点的指针,以此位置向后遍历单链表,删除相同结点,以此类推。
void RemoveAll(pLinkList* pHead,DataType d)//删除所有相同结点
{
pLinkNode cur = *pHead;
pLinkNode del = NULL;
pLinkNode prev = NULL;
assert(pHead);
while(cur)
{
if(cur->data == d)
{
del = cur;
if(cur == *pHead)
{
*pHead = (*pHead)->next;
cur = *pHead;
}
else
{
prev->next = cur->next;
cur = prev->next;
}
free(del);
}
else
{
prev = cur;
cur = cur->next;
}
}
}

//删除指定位置的结点,需找到要删除结点的上一个结点,将该结点的下一个结点赋给该结点的next,删除并释放该结点。
void Erase(pLinkNode* pHead,pLinkNode pos)//删除指定位置的结点
{
pLinkNode cur = *pHead;
pLinkNode del = NULL;
assert(pHead);
if(*pHead == NULL)
{
return;
}
else if(*pHead == pos)
{
free(*pHead);
*pHead =NULL;
}
else
{
while(cur->next)
{
if(cur->next == pos)
{
del = cur->next;
cur->next = del->next;
free(del);
del = NULL;
}
cur = cur->next;
}
}
}

//删除无头单链表的非尾结点,首先给出一个指针del记录pos->next,将pos->data赋给pos->data,再将del->next赋给pos->next,最后只需把del释放即可
void EraseNotTail(pLinkNode pos)//删除无头单链表的非尾结点
{
pLinkNode del = pos->next;
pos->data = del->data;
pos->next = del->next;
free(del);
del = NULL;
}

//单链表的逆序,把第一个结点取出来,他的next恒等于NULL,然后再把其他结点依次取出来利用头插的方法插入,完成逆序。
void ReverseList(pLinkList* pHead)//反转(逆序)
{
pLinkNode pNewHead = NULL;
pLinkNode cur = *pHead;
pLinkNode prev = NULL;
assert(pHead);
if((cur == NULL)&&(cur->next == NULL))
{
return;
}
while(cur)
{
prev = cur;
cur = cur->next;
prev->next = pNewHead;
pNewHead = prev;
}
*pHead = pNewHead;
}

//冒泡排序
void BubbleSort(pLinkList* pHead)//排序链表(冒泡)
{
pLinkNode cur = *pHead;
assert(pHead);
while(cur)
{
pLinkNode pos =cur->next;
while(pos)
{
if(cur->data > pos->data)
{
DataType tmp = cur->data;
cur->data = pos->data;
pos->data = tmp;
}
pos = pos->next;
}
cur = cur->next;
}
}

//在当前结点前插入一个结点,首先在pos位置后插入一个结点,然后再交换pos->data和newNode->data即可
void InsertFrontNode(pLinkNode pos,DataType d)//在当前结点前插入一个数据
{
pLinkNode NewNode = BuyNode(d);
DataType tmp = 0;
assert(pos);
NewNode->next = pos->next;
pos->next = NewNode;
tmp = pos->data;
pos->data = NewNode->data;
NewNode->data = tmp;
}

//合并两个有序链表(非递归)
pLinkNode Merge(pLinkList l1,pLinkList l2)
{
pLinkNode newHead = NULL;
pLinkNode cur = NULL;
if(l1 == l2)
{
return l1;
}
if((l1 != NULL)&&(l2 ==NULL))
{
return l1;
}
if((l1 == NULL)&&(l2 != NULL))//确定头节点
{
return l2;
}
if(l1->data < l2->data)
{
newHead = l1;
l1 = l1->next;
}
else
{
newHead =l2;
l2 = l2->next;
}
cur = newHead;
while ((l1)&&(l2))
{
if(l1->data < l2->data)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
if(l1)
{
cur->next = l1;
}
else
{
cur->next =l2;
}
return newHead;
}

//利用递归实现链表的合并

pLinkNode _Merge(pLinkList plist1,pLinkList plist2)
{
pLinkNode newHead = NULL;
if((plist1 == NULL) &&(plist2 == NULL))
{
return NULL;
}
else if((plist1 != NULL)&&(plist2 == NULL))
{
return plist1;
}
else if((plist1 == NULL)&&(plist2 != NULL))
{
return plist2;
}
if(plist1->data < plist2->data)
{
newHead = plist1;
newHead->next = _Merge(plist1->next,plist2);
}
else
{
newHead = plist2;
newHead->next = _Merge(plist1,plist2->next);
}
return newHead;
}

//利用快慢指针,快指针走两步,慢指针走一步,返回慢指针,即为中间结点
pLinkNode FindMidNode(pLinkList* pHead)//查找链表的中间结点
{
pLinkNode fast = *pHead;
pLinkNode slow = *pHead;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}

//利用快慢指针,快指针先走k-1步后,两指针同时走,慢指针即为倒数第k个结点,然后再利用删除无头单链表的非尾结点中的方法删除慢指针的下一个结点。
void DelKNode(pLinkList *pHead,int k)//删除单链表的倒数第k(k>1)个结点
{
pLinkNode fast = *pHead;
pLinkNode slow = *pHead;
pLinkNode del = NULL;
assert(*pHead);
assert(k>1);
while (--k)
{
fast = fast->next;
}
while(fast->next)
{
fast = fast->next;
slow = slow->next;
}
del = slow->next;
slow->data = slow->next->data;
slow->next = slow->next->next;
free(del);
}

//约瑟夫环,n个人围成一圈,从某个人开始报数,报到m的那个人退出,然后m的下一个人继续从1开始报数,报到m的那个人退出,以此类推,最后剩下的那个人胜出。

//设置一个指针变量指向第一个结点,从第一个结点先走(num-1)步,利用删除单链表的无头非尾结点的方法,删除num结点的下一个结点,依次类推。
pLinkNode JosephCycle(pLinkList *pHead,int num)
{
pLinkNode cur = *pHead;
pLinkNode del = NULL;
int count = 0;
assert(pHead);
while(1)
{
count = num;
if(cur->next == cur)
{
break;
}
while(--count)
{
cur = cur->next;
}
printf("%d ",cur->data);
del = cur->next;
cur->data = cur->next->data;
cur->next = cur->next->next;
free(del);
}
*pHead = cur;
return cur;
}

//利用快慢指针,快指fast针走两步,慢指针slow走一步,只要(fast == slow),返回slow,则单链表带环,否则不带环。
pLinkNode CheckCycle(pLinkList pList)//判断链表是否带环
{
pLinkNode fast = pList;
pLinkNode slow = pList;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
return slow;
}
}
return NULL;
}

//增加一个计数器,从相遇结点在遍历一遍环即可求的环的长度
int GetCircleLength(pLinkNode meet)//若带环则根据相遇结点求环的长度
{
int count = 0;
pLinkNode pos = meet;
do
{
pos = pos->next;
count++;
}while (pos != meet);
return count;
}

//增设两个指针,一个指向单链表的第一个结点,一个指向相遇结点,只要两者不等,同时各走一步,终有一次两者相等,则返回环的入口结点
pLinkNode GetCycleEntryNode(pLinkList pList,pLinkNode meetNode)//获取环的入口结点
{
pLinkNode entry = pList;
pLinkNode meet = meetNode;
while (entry != meet)
{
entry = entry->next;
meet = meet->next;
}
return entry;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息