用 C 语言实现一个单链表,包含链表的创建、遍历、插入、删除、排序、反转等常用操作
# include<stdio.h>
# include<stdlib.h>
# include<malloc.h>
//定义链表节点结构体
struct Node
{
int data;
struct Node * pNext;
};
//函数声明
struct Node * createLinkedList(void);
void traverseLinkedList(struct Node * pHead);
bool isEmptyLinkedList(struct Node * pHead);
int getLinkedListSize(struct Node * pHead);
void sortLinkedList(struct Node * pHead);
bool insertLinkedList(struct Node * pHead, int pos, int val);
bool deleteLinkedList(struct Node * pHead, int pos, int * val);
struct Node * reverseLinkedList(struct Node * pHead);
void traverseLinkedList2(struct Node * pHead);//用于链表翻转后的遍历输出
int main(void)
{
struct Node * pHead = NULL;
pHead = createLinkedList();
traverseLinkedList(pHead);
if (isEmptyLinkedList(pHead))
{
printf("链表为空\n");
}
else
{
int length = getLinkedListSize(pHead);
printf("链表不为空,链表的长度为 len= %d \n",length);
sortLinkedList(pHead);
printf("排序后的链表\n");
traverseLinkedList(pHead);
insertLinkedList(pHead,1,666);
printf("插入新节点后的链表\n");
traverseLinkedList(pHead);
length = getLinkedListSize(pHead);
printf("插入新节点后的链表长度为 len= %d \n",length);
// int val;
// deleteLinkedList(pHead,2,&val);
// printf("删除节点%d后的链表\n",val);
// traverseLinkedList(pHead);
struct Node * reverseHead = reverseLinkedList(pHead);
printf("反转后的链表\n");
traverseLinkedList(reverseHead);
printf("\n=================\n");
insertLinkedList(reverseHead,0,777);
printf("插入新节点后的链表\n");
traverseLinkedList(reverseHead);
}
return 0;
}
struct Node * createLinkedList(void)
{
int len;//链表长度
int i;
int val;
//创建头指针,指向头结点
struct Node * pHead = (struct Node *)malloc(sizeof(struct Node));
if (pHead == NULL)
{
printf("create failed!");
exit(-1);
}
//定义一个尾指针,永远指向最后一个节点
struct Node * pTail = pHead;
pTail->pNext = NULL;//初始时刻,头结点指针域和数据域都为空,避免垃圾值
pTail->data = NULL;
printf("please input the length of list: len= ");
scanf("%d",&len);
//循环创建链表
for (i=0; i<len; i++)
{
struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));
printf("please input the %d list value:",i+1);
scanf("%d",&val);
pNew->data = val;
pTail->pNext = pNew;
pTail = pNew;
pTail->pNext = NULL;
}
return pHead;
}
void traverseLinkedList(struct Node * pHead)
{
struct Node * p = pHead;//定义 一个指针p指向头结点,用于循环遍历输出
//兼容反转后的链表也能输出
if (p->data == NULL)
p = p->pNext;
while (p != NULL)
{
printf("%d ",p->data);
p = p->pNext;
}
//用这种方式不太好,一个循环下来改变了pHead的值
// while (pHead->pNext != NULL)
// {
// printf("%d ",pHead->pNext->data);
// pHead = pHead->pNext;
// }
printf("\n");
return ;
}
bool isEmptyLinkedList(struct Node * pHead)
{
if (pHead->pNext != NULL)
{
return false;
}
else
{
return true;
}
}
int getLinkedListSize(struct Node * pHead)
{
int len=0;
//先判断链表是否为空
if (isEmptyLinkedList(pHead))
{
len = 0;
return len;
}
while (pHead->pNext != NULL)
{
len++;
pHead = pHead->pNext;
}
return len;
}
void sortLinkedList(struct Node * pHead)
{
int i,j,tmp;
struct Node * p;
struct Node * q;
int length = getLinkedListSize(pHead);
for (i=0,p=pHead->pNext; i<length; i++,p=p->pNext)
{
for (j=i+1,q=p->pNext; j<length; j++,q=q->pNext)
{
if (p->data > q->data)
{
tmp = p->data;
p->data = q->data;
q->data = tmp;
}
}
}
}
bool insertLinkedList(struct Node * pHead, int pos, int val)
{
int i=0;
struct Node * p = pHead;
//执行完while语句,此时的p已经指向了pos前的一个节点
while (p != NULL && i<pos-1)// 1 2 3 4 5
{
p = p->pNext;
i++;
}
if (i>pos-1 || p==NULL)
{
return false;
}
//pos=1直接从这里开始执行
struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));
if (NULL == pNew)
{
printf("create failed!\n");
exit(-1);
}
pNew->data = val;
pNew->pNext = p->pNext;
p->pNext = pNew;
return true;
}
bool deleteLinkedList(struct Node * pHead, int pos, int * val)
{
int i = 0;
struct Node * p = pHead;//此时p指向头结点,注意是头结点
//比如要删除pos=2的节点,经过while循环后,p已经指向了首节点,首节点的指针域保存的下一个节点(也就是pos=2)的地址
while (p->pNext!=NULL && i<pos-1)
{
p = p->pNext;
i++;
}
if (i>pos-1 || p==NULL)
{
return false;
}
*val = p->pNext->data;
p->pNext = p->pNext->pNext;
return true;
}
struct Node * reverseLinkedList(struct Node * pHead)
{
/*
带有头结点和尾节点的链表反转后对比:
反转前:头结点数据域不存任何值,指针域保存下一节点的地址,尾节点指针域为空
反转后:头结点数据域有值,指针域保存下一节点的地址,尾节点指针域为空
反转后没有了头结点
*/
if (pHead==NULL || pHead->pNext == NULL)
{
return pHead;
}
pHead = pHead->pNext;//首先跳过头结点,此时pHead指向了首节点
struct Node * curNode = pHead;//curNode指向了首节点
struct Node * preNode = NULL;
while (curNode)
{
//第一次循环后,curNode指向了首节点的下一个节点,preNode指向了首节点
//第二次循环后,curNode指向的那个节点的指针域保存了preNode节点的地址(既首节点的地址),所以首节点的下一个节点指向了首节点,并且curNode和preNode分别后移一位
//依次循环,直到最后。。
struct Node * tmpNode = curNode->pNext;
curNode->pNext = preNode;
preNode = curNode;
curNode = tmpNode;
}
return preNode;
}