数据结构链表,属于线性表的一部分,在数据结构中占有举足轻重的地位,对链表的理解将直接影响后期包括树、二叉树等一系列内容。
以下仅为个人在学习过程中对该内容的个人理解,其中查阅了部分资料,仅供各位学习参考,希望能给和我一样新学习的同学带来帮助,如有错误,还请指正。
链表相对顺序表的优点:
- 增删查改的高灵活性
- 内存空间的利用效率更高
相对顺序表缺点:
- 可能导致内存碎片化
- 访问没有随机性
链表对应操作:
- 初始化
- 创建链表
- 求表长
- 按序号查找
- 按值查找
- 插入链表
- 链表的置空
- 链表的遍历
- 链表的删除
1.初始化
LIST* Initlist(LIST* hate)
{
hate = (LIST *)malloc(sizeof(LIST));
Ifmalloc(hate);
hate->next = NULL;
return hate;
}
分配空间后置空即可。
其中的Ifmalloc(hate)为检验分配空间是否成功的操作,代码为:
void Ifmalloc(LIST* hate)
{
if (hate == NULL)
{
hate = (LIST*)malloc(sizeof(LIST));
Ifmalloc(hate);
}
}
2.创建链表
void Creatlist(LIST* hate, int num)//分别是链表的头节点和准备需要的节点数
{
//hate为头节点
LIST* tail;
LIST *pnew;//普通节点
tail = hate;
printf("请依次输入链表的元素:\n");
while (num--)
{
pnew = (LIST *)malloc(sizeof(LIST));
Ifmalloc(hate);
scanf("%d", &pnew->data);
tail->next = pnew;
tail = pnew;
}
pnew->next = NULL;
}
采用了一次性创建一定数量的方式,用以提高代码的灵活性。插入方式采取的尾插法。
头指针,头节点,首元节点,尾节点
头指针:指向头节点的指针,就是可以通过这个指针找到整个链表。
头节点:在首元节点前面,只有指针部分,指向首元节点。
首元节点:就是首个存数据的节点,是链表的第一个节点。
尾节点:最后一个节点,指针域为空NULL。
3.求表长
int Listlen(LIST* hate)
{
int len = 0;
LIST* p = hate;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
4.按序号查找
void Getlist(LIST* hate)
{
LIST* p = hate;
int num = 0;
int len = 0;
printf("请输入您要查找的元素序号:\n");
scanf("%d", &num);
len = Listlen(hate);
if (num > 0 & num <= len)
{
while (num--)
{
p = p->next;
}
printf("%d\n", p->data);
}
else
{
printf("您的输入有误,请重新输入。\n");
Getlist(hate);
}
}
5.按值查找
void Getelem(LIST* hate)
{
int num = 0;
int sum = 0;
printf("请输入您要查找的元素:\n");
scanf("%d", &num);
while (hate->next != NULL)
{
hate = hate->next;
sum++;
if (hate->data == num)
{
printf("%d为该元素的序号位置。\n", sum);
return;
}
}
printf("在链表中没有该元素\n");
}
6.插入链表
bool Linklist(LIST* hate)
{
LIST *p,*pnew,*tail;
int num = 0;
tail = hate;
pnew = (LIST*)malloc(sizeof(LIST));
if (pnew == NULL)
return false;
printf("请输入您要插入的位置:\n");
scanf("%d", &num);
while (num-1)
{
tail = tail->next;
num = num - 1;
}
printf("请输入您要插入的元素:\n");
scanf("%d", &pnew->data);
p = tail->next;
if (p->next != NULL);
tail->next = pnew;
pnew->next = p;
return true;
}
此处使用了bool数据类型,它的返回值只有两种:即true和false,但是如果返回0,其实返回的也是false,返回其他大于等于1的数就是true,用这个的目的只是尝试。
7.链表的置空
void Clearlinklist(LIST* hate)
{
LIST* p = NULL;
while (hate->next != NULL)
{
p = hate->next;
hate->next = p->next;
free(p);
}
}
8.链表的遍历
void Travellist(LIST* hate)
{
LIST* p = hate;
while (p->next != NULL)
{
p = p->next;
printf("%d\n", p->data);
}
}
9.链表的删除
void Dellist(LIST* hate)
{
LIST* tail = hate;
LIST* p = NULL;
int num = 0;
printf("请输入您要删除的链表位置:\n");
scanf("%d", &num);
while (num - 1)
{
tail = tail->next;
num = num - 1;
}
p = tail->next;
tail->next = p->next;
free(p);
}
代码整体
#include<stdio.h>
#include<malloc.h>
//定义结构体类型
struct List
{
int data;
struct List* next;
};
typedef struct List LIST;
LIST* Initlist(LIST* hate);//初始化链表
void Ifmalloc(LIST* hate);//检验地址分配是否有误
void Creatlist(LIST* hate, int num);//创建一定长度的链表
void Travellist(LIST* hate);//遍历链表
bool Linklist(LIST* hate);//插入链表
void Dellist(List* hate);//删除链表
int Listlen(LIST* hate);//求表格长度
void Getlist(LIST* hate);//按照序号查找元素
void Getelem(LIST* hate);//按照元素值查找
void Clearlinklist(LIST* hate);//清空链表
//判断空间分配是否完成
void Ifmalloc(LIST* hate)
{
if (hate == NULL)
{
hate = (LIST*)malloc(sizeof(LIST));
Ifmalloc(hate);
}
}
//初始化头节点
LIST* Initlist(LIST* hate)
{
hate = (LIST *)malloc(sizeof(LIST));
Ifmalloc(hate);
hate->next = NULL;
return hate;
}
//单链表的建立
void Creatlist(LIST* hate, int num)//分别是链表的头节点和准备需要的节点数
{
LIST* tail;
LIST *pnew;
tail = hate;
printf("请依次输入链表的元素:\n");
while (num--)
{
pnew = (LIST *)malloc(sizeof(LIST));
Ifmalloc(hate);
scanf("%d", &pnew->data);
tail->next = pnew;
tail = pnew;
}
pnew->next = NULL;
}
//遍历链表
void Travellist(LIST* hate)
{
LIST* p = hate;
while (p->next != NULL)
{
p = p->next;
printf("%d\n", p->data);
}
}
//插入链表元素
bool Linklist(LIST* hate)
{
LIST *p,*pnew,*tail;
int num = 0;
int len = 0;
tail = hate;
pnew = (LIST*)malloc(sizeof(LIST));
if (pnew == NULL)
return false;
len = Listlen(hate);
while (1)
{
printf("请输入您要插入的位置:\n");
scanf("%d", &num);
if (num <= len + 1 && num > 0)
{
while (num - 1)
{
tail = tail->next;
num = num - 1;
}
printf("请输入您要插入的元素:\n");
scanf("%d", &pnew->data);
p = tail->next;
if (p->next != NULL);
tail->next = pnew;
pnew->next = p;
return true;
}
else
{
printf("您的输入有误,请重新输入:\n");
}
}
}
//删除链表元素
void Dellist(LIST* hate)
{
LIST* tail = hate;
LIST* p = NULL;
int num = 0;
printf("请输入您要删除的链表位置:\n");
scanf("%d", &num);
while (num - 1)
{
tail = tail->next;
num = num - 1;
}
p = tail->next;
tail->next = p->next;
free(p);
}
//求链表当前长度
int Listlen(LIST* hate)
{
int len = 0;
LIST* p = hate;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
//按照序号查找元素
void Getlist(LIST* hate)
{
LIST* p = hate;
int num = 0;
int len = 0;
printf("请输入您要查找的元素序号:\n");
scanf("%d", &num);
len = Listlen(hate);
if (num > 0 & num <= len)
{
while (num--)
{
p = p->next;
}
printf("%d\n", p->data);
}
else
{
printf("您的输入有误,请重新输入。\n");
Getlist(hate);
}
}
//按照元素查找序号
void Getelem(LIST* hate)
{
int num = 0;
int sum = 0;
printf("请输入您要查找的元素:\n");
scanf("%d", &num);
while (hate->next != NULL)
{
hate = hate->next;
sum++;
if (hate->data == num)
{
printf("%d为该元素的序号位置。\n", sum);
return;
}
}
printf("在链表中没有该元素\n");
}
//清空链表
void Clearlinklist(LIST* hate)
{
LIST* p = NULL;
while (hate->next != NULL)
{
p = hate->next;
hate->next = p->next;
free(p);
}
}
//目录
void mune()
{
printf("******创建链表输入‘1’*******遍历链表输入‘2’\n");
printf("******插入节点输入‘3’*******删除节点输入‘4’\n");
printf("******求链表长输入‘5’*******按号查找输入‘6’\n");
printf("******按值查找输入‘7’*******清空链表输入‘8’\n");
}
int main()
{
LIST* hate;
hate = (LIST*)malloc(sizeof(LIST));
int num = 0;
int ch = 1;
while (ch)
{
mune();
scanf("%d", &ch);
switch (ch)
{
case 1:
printf("您需要创建的链表长度:\n");
scanf("%d", &num);
Creatlist(hate, num);
break;
case 2:
Travellist(hate);
break;
case 3:
Linklist(hate);
break;
case 4:
Dellist(hate);
break;
case 5:
printf("%d\n", Listlen(hate));
break;
case 6:
Getlist(hate);
break;
case 7:
Getelem(hate);
break;
case 8:
Clearlinklist(hate);
break;
}
}
return 0;
}
以上为全部代码,对于链表的理解个人认为最为重要的是理解链表的创建部分,只要理解了链表之间是如何链接创建的以下代码自己打出来是没有问题的。
在创建链表的过程中,我认为hate头节点也只是起一个索引的作用,后面一个个节点的创建主要依靠tail作为媒介,一步步创建下去。
以上只为个人见解,仅供参考=0=