单链表完整实现
Posted gmengshuai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单链表完整实现相关的知识,希望对你有一定的参考价值。
#include <stdio.h>
#include <stdlib.h>
/* 定义结构体 */
typedef struct Node
{
int data; //数据域
struct Node * pNext;//指针域
}NODE, * PNODE; //由于使用了typedef, 所以NODE <=> struct Node , PNODE <=> struct Node *
/* 函数声明 */
void test01();
PNODE create_list(); //创建一个链表
void traverse_list(PNODE pHead); //遍历整个链表并输出
bool is_empty(PNODE pHead); //判断链表是否为空
int length_list(PNODE pHead); //链表的长度
bool insert_list(PNODE pHead, int pos, int value); //链表的插入
bool delete_list(PNODE pHead, int pos, int * pval); //链表的删除
void sort_list(PNODE pHead); //链表的排序
/* 主函数 */
int main()
{
test01();
return 0;
}
/* 调用函数 */
void test01()
{
PNODE pHead = NULL; //头指针为空,用来保存头结点的地址
int val; //用来保存删除的元素
pHead = create_list(); //创建一个链表,并返回头结点的地址给pHead
traverse_list(pHead); //遍历整个链表
if(is_empty(pHead)) //判断链表是否为空
{
printf("链表为空
");
}
else
{
printf("链表不空
");
}
int len = length_list(pHead);
printf("链表的长度为:%d
", len);
sort_list(pHead);
printf("链表排序后");
traverse_list(pHead);
insert_list(pHead, 2, 66);
printf("链表插入后");
traverse_list(pHead);
if( delete_list(pHead, 2, &val) )
{
printf("删除成功,您删除的元素是:%d
", val);
}
else
{
printf("删除失败!您删除的元素不存在!
");
}
printf("链表删除后");
traverse_list(pHead);
}
/*———————————————————————————————————————————————————————*/
PNODE create_list()
{
int len; //用来存放有效节点的个数
int i;
int temp_val; //临时存放用户输入结点数据域的值
PNODE pNew;
//分配一个不存放有效数据的头结点
PNODE pHead = (PNODE)malloc(sizeof(NODE));
if(NULL == pHead)
{
printf("分配失败,程序终止!");
exit(-1);
}
PNODE pTemp = pHead; //临时存放头结点的地址
pTemp->pNext = NULL;
printf("请输入您要生成的链表节点的个数: len = ");
scanf("%d", &len);
for(i = 0; i<len; i++)
{
printf("请输入第%d个节点数据域的值 :", i+1);
scanf("%d", &temp_val);
//循环一次分配一个存放有效数据的结点
pNew = (PNODE)malloc(sizeof(NODE));
if(NULL ==pNew)
{
printf("分配失败,程序终止!");
exit(-1);
}
pNew->data = temp_val;
//尾插法
pTemp->pNext = pNew;
pNew->pNext = NULL; //每分配一个结点,这个结点就是最后一个,所以它的指针域(pNext)为空
pTemp = pNew; //保证前一个结点的指针域都指向后一个结点
}
return pHead; //返回头结点的地址
}
/*———————————————————————————————————————————————————————*/
void traverse_list(PNODE pHead)
{
PNODE p = pHead->pNext; //头结点的指针域赋给p,即首结点赋给p 【注意区分头结点和首结点】
printf("链表的数据为:
");
while(NULL != p)
{
printf("%d ", p->data);
p = p->pNext; //下一个结点赋给p
}
printf("
");
return;
}
/*———————————————————————————————————————————————————————*/
bool is_empty(PNODE pHead)
{
if(NULL == pHead->pNext)
{
return true;
}
else
{
return false;
}
}
/*———————————————————————————————————————————————————————*/
int length_list(PNODE pHead)
{
PNODE p = pHead->pNext;//pNext是struct Node * 类型,p也应该是struct Node * 类型
int count = 0;
while(NULL != p) //只要指针域指向的不是空结点就不结束
{
count++;
p = p->pNext;
}
return count;
}
/*———————————————————————————————————————————————————————*/
//数组与链表存储方式虽不同,但是它们的算法是一样的
void sort_list(PNODE pHead)
{
//数组排序
/*
int i, j, t;
int len = length_list(pHead);
for(i = 0; i<len; i++)
{
for(j = i+1; j<len; j++)
{
if(a[i]>a[j])
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
*/
//链表排序
int t;
PNODE p, q;
for(p = pHead->pNext; NULL != p; p = p->pNext)//由于最后一个结点的指针域为空,所以可作为循环结束的条件
{
for(q = p->pNext; NULL != q; q = q->pNext)//注意和数组进行比较,思想都是一样的
{
if(p->data>q->data)
{
t = p->data;
p->data = q->data;
q->data = t;
}
}
}
return;
}
/*———————————————————————————————————————————————————————*/
//链表的插入不存在满的情况
//在pHead所指向链表的第pos个节点的前面插入一个新的结点,假定pos为3
bool insert_list(PNODE pHead, int pos, int value)
{
int i = 0;
PNODE p = pHead;
while(NULL != p && i<pos-1) //i<3-1=2, 取值为0、1,循环执行了两次,p指向了第二个有效结点
{
p = p->pNext;
i++;
}
if(NULL == p || i>pos-1)
{
return false;
}
//如果程序能执行到这一行说明p已经指向了第pos-1个结点,但第pos-1个节点是否存在无所谓
//分配需要插入的结点
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL == pNew)
{
printf("动态分配内存失败!");
exit(-1);
}
pNew->data = value;
//将新的结点存入p节点的后面【即第pos个节点的前面】,若没明白请回头学习如何插入节点
PNODE q;
q = p->pNext;
p->pNext = pNew;
pNew->pNext = q;
return true;
}
/*———————————————————————————————————————————————————————*/
//删除第pos个结点,假定pos为3
bool delete_list(PNODE pHead, int pos, int * pval)
{
int i = 0;
PNODE p = pHead;
while(NULL != p->pNext && i<pos-1)//i<3-1=2, 取值为0、1,循环执行了两次,p指向了第二个结点
{
p = p->pNext;
i++;
}
if(NULL == p->pNext && i>pos-1)
{
return false;
}
//如果程序能执行到这一行说明p已经指向了第pos-1个结点,并且第pos个节点是存在的
//这里的指向解释一下:通俗的说就是等于这个结点的意思
PNODE q = p->pNext; //q指向待删除的结点
*pval = q->data; //返回删除的值
//删除p节点后面的结点,若没明白请回头学习如何删除节点
p->pNext = p->pNext->pNext;
free(q); //释放q所指向的节点所占的内存
q = NULL; //q = p->pNext = NULL,表示p指针域指向的结点已被删除
return true;
}
/*———————————————————————————————————————————————————————*/
以上是关于单链表完整实现的主要内容,如果未能解决你的问题,请参考以下文章