您的位置:首页 > 理论基础 > 数据结构算法

数据结构----单链表的创建、插入、删除、读取、遍历

2018-02-07 17:21 447 查看
阅读《大话数据结构》关于链表的章节后,自己尝试写出了链表的几个函数,在微博进行记录。
代码如下:
#include <stdio.h>
#include <malloc.h>

//创建链表结构体
typedef struct Node
{
int data;
struct Node *next;
}Node;
typedef Node* LinkList; //定义LinkList的数据类型为Node*

//尾插法创建链表,表头后有n个结点
void CreateListHead(LinkList *L,int n)
{
int i;
LinkList p, q;

*L = (LinkList)malloc(sizeof(Node)); //申请头结点的内存空间

p = *L;
p->data = n; //头结点数据域,存储链表的数据的长度

for (i = 0; i < n; i++)
{
q = (LinkList)malloc(sizeof(Node));
q->data = i+1; //给新建的结点的数据域赋值
p->next = q; //末尾结点的指针域指向新创建的结点
p = q; //p指针缓存q的地址,下一循环中p->next,即为q->next,使本循环中q的指针域指向下一结点
}
p->next = NULL; //尾结点指针域为空
}

//获取链表中第i个结点的数据并返回给e,i为0取的是头结点数据域(除头结点外,结点的个数)
int GetElem(LinkList L,int i,int* e)
{
LinkList p;

p = L;

while(p && i--) //找到第i个结点
{
p = p->next;
}

if(!p) return 0; //第i个结点为空,报错

*e = p->data; //将第i个结点的数据赋值给*e

return !0;
}

//在链表头结点后第i个结点位置插入一个节点,数据域为e,原结点后移
int ListInsert(LinkList *L,int i,int e)
{
LinkList p,q;

if ( i < 1) return 0; //i为0,报错

q = *L;

while (q && --i) //寻找第i-1个结点的位置
{
q = q->next;
}

if (!q) return 0; //i-1结点为空,报错

p = (LinkList)malloc(sizeof(Node)); //p申请内存空间,应在找到i-1结点后申请,否则可能因报错浪费内存空间

p->next = q->next; //新建结点的指针域 = i-1位置结点的指针域
q->next = p; //i-1位置结点的指针域指向新建的结点
p->data = e; //新建结点的数据域为e

(*L)->data++; //链表长度+1

return !0;
}

//删除链表头结点后第i个结点,并将该结点数据返回给*e
int ListDelete(LinkList *L,int i,int* e)
{
LinkList p, q;

if (i < 1) return 0; //i为0,报错

q = *L;

while (q && --i) //寻找第i-1结点
{
q = q->next;
}

if (!q->next) return 0; //i-1结点指针域为空,即第i个结点不存在,报错

p = q;
p = p->next; //p为第i个结点
*e = p->data; //将第i个结点的数据返回给*e
q->next = p->next; //将i-1结点的指针域变为第i个结点的指针域

free(p); //释放第i结点的内存

(*L)->data--; //链表长度减一

return !0;
}

//遍历链表数据(包括头结点)
void PrintfList(LinkList L)
{
LinkList p;

p = L; //直接遍历链表L,会使L不再指向头结点
while (p) //当L为NULL时,停止打印DATA
{
printf("%d\n", p->data);
p = p->next;
}
}

main()
{
int temp;
LinkList L;

CreateListHead(&L, 5); //创建一个链表,头结点后有5个结点
printf("创建的链表为:\n");
PrintfList(L);

if (ListInsert(&L, 6, 100)) //在第6个结点位置插入数据为100的结点
{
printf("在第6个结点位置插入结点后链表为:\n");
PrintfList(L);
}
else
{
printf("在第6个结点位置插入结点失败\n");
}

if (ListDelete(&L, 1, &temp)) //删除头结点后第1个结点
{
printf("删除第1结点后链表为:\n");
PrintfList(L);
printf("删除的结点的数据为:%d\n", temp);
}
else
{
printf("删除第1结点失败\n");
}

if (GetElem(L, 4, &temp)) //读取头结点后第4个结点的数据
{
printf("读取头结点后第4个结点数据为:\n");
printf("%d\n", temp);
}
else
{
printf("读取头结点后第4个结点数据失败\n");
}

getch(); //等待用户按键
}

编译的环境为VS2015,运行结果如下图:



这里需要注意的是,传递进函数里面的结构体指针变量,是传递它本身还是传递它的地址。
如:CreateListHead();函数,如果传递进去的不是&L而是L,是无法创建成功链表的。
具体参考:http://blog.csdn.net/a3748622/article/details/79286974
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐