单链表
1.单链表结构体
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
LNOde *L; 可读性不强,代表的是一个指向头结点的指针 但通常不知道它是一个结点还是一个指向头结点的指针
LinkList L; 可读性较强,代表的是一个指向头结点的指针 主要可以和一个新的结点,和指向头结点的指针区别开来
2.初始化单链表
void InitLinkList(LinkList L)
{
L->data = 0; // 存储表长
L->next = NULL;
}
在初始化链表的同时其实是在初始化头结点,我们需要在main函数里面给头结点分配内存空间
int main()
{
LinkList L;
L = (LNode*)malloc(sizeof(LNode)); // 分配内存空间
return 0;
}
3.打印单链表
void PrintfLinkList(LinkList L)
{
LNode *p;
p = L;
while (p->next != NULL)
{
p = p->next;
printf("%d-->", p->data);
}
printf("NULL\n");
}
打印的本质是利用循环,一直找到结点的下一个为NULL的情况下,停止循环
4.头插法
void InsertLinkListHeadNode(LinkList L)
{
LNode *newNode; // 新节点
ElemType newNode_data; // 新节点的数据域
// 设置9999为结束条件
printf("please enter to number(9999 mean exit)\n");
scanf("%d", &newNode_data);
while (newNode_data != 9999)
{
newNode = (LNode *)malloc(sizeof(LNode));
newNode->next = L->next;
L->next = newNode;
newNode->data = newNode_data;
L->data++; // 表长+1
printf("please enter to number(9999 mean exit)\n");
scanf("%d", &newNode_data);
}
}
以9999为结束循环的条件,不断在头部插入结点
5.尾插法
void InsertLinkListTailNode(LinkList L)
{
LNode *newNode;
ElemType newNode_data;
LNode *TailNode = L; // 代表指向尾节点的指针
// 循环找到最后一个节点
while (TailNode->next != NULL)
{
TailNode = TailNode->next;
}
printf("please enter a number(9999 mean exit)\n");
scanf("%d", &newNode_data);
while (newNode_data != 9999)
{
newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = newNode_data;
TailNode->next = newNode;
newNode->next = NULL;
TailNode = newNode; // 让插入尾部的节点变成尾节点
L->data++;
printf("please enter a number(9999 mean exit)\n");
scanf("%d", &newNode_data);
}
}
因为结点是从头结点开始的,所以要通过循环一直找到最后的一个结点,插入结点后,插入的这个结点就成了新的尾结点
6.按位查找
LNode *GetElem(LinkList L, int i)
{
if (i == 0)
{
printf("The LinkList's element you are looking for does not exist\nReturn the head pointer of the LinkList!\n ");
return L;
}
// 数组下标超界
else if (i < 0 || i > L->data)
{
printf("The LinkList's element you are looking for does not exist\nReturn NULL!\n ");
return NULL;
}
else
{
LNode *p;
p = L;
for (int j = 0; j < i; j++)
{
p = p->next;
}
return p;
}
}
7.按值查找
// 单链表按值查找
LNode *LocateELem(LinkList L, ElemType e)
{
if (!L->next)
{
printf("LinkList is empty\n");
return NULL;
}
LNode *p;
p = L;
while (p->next != NULL)
{
p = p->next;
if (p->data == e)
return p;
}
printf("not find number\n");
return NULL;
}
8.按位插入
// 单链表按位插入
ElemType LocatInsertLinkList(LinkList L, int i, ElemType e)
{
if (i < 1 || i > L->data + 1)
{
printf("The position of the element to be inserted is invalid\n");
return 0;
}
LNode *p = GetElem(L, i - 1);
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = e;
newNode->next = p->next;
p->next = newNode;
L->data++;
return 1;
}
通过按位查找找到想查找的位置的前一个位置,在进行插入操作
9.按位删除
// 单链表按位删除
ElemType LocateDeleteLinkList(LinkList L, int i, ElemType *e)
{
if (!L || !L->next)
{
printf("The LinkList is empty\n");
*e = 9999;
return 0;
}
if (i < 1 || i > L->data)
{
printf("The position of the element to be deleted is invalid\n");
*e = 9999;
return 0;
}
LNode *p = GetElem(L, i - 1);
LNode *q = p->next;
p->next = q->next;
*e = q->data;
free(q);
L->data--;
return 1;
}
也是通过GetElem函数找到前一个位置,在来改变结点的指向,并且通过free函数来将结点释放掉,达到删除结点的操作
10.销毁链表
void DestroyLinkList(LinkList L)
{
LNode *p, *q;
p = L;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
L = NULL;
printf("LinkList destroyed\n");
}
11.测试
int main()
{
LinkList L; // L是一个指向头节点的指针
L = (LNode *)malloc(sizeof(LNode)); // 分配内存空间
InitLinkList(L); // 初始化链表
// printf("%d \n", L->data); // 0
// 测试头插法
// InsertLinkListHeadNode(L);
// PrintfLinkList(L);
// 测试尾插法
InsertLinkListTailNode(L);
PrintfLinkList(L);
// printf("%d\n", GetElem(L, 3)->data);
// printf("%d\n", LocateELem(L, 3)->data);
// 测试按位插入
// LocatInsertLinkList(L, 1, 9999);
// PrintfLinkList(L);
// PrintfLinkList(L);
// 测试按位删除
// ElemType e;
// LocateDeleteLinkList(L, 2, &e);
// printf("e=%d\n", e);
// PrintfLinkList(L);
// 测试销毁单链表
DestroyLinkList(L);
// 注意:销毁链表后在打印链表会报错
PrintfLinkList(L); // error
return 0;
}