C指针实现单链表,主函数调用
使用数组或者指针简单实现的表都有其不同的优缺点,例如数组的比较方便查询,不方便修改,指针的比较方便修改但不方便查询,同时需要额外空间存放指针……之后会有一种 间接寻址方法实现表 结合了以上两种方式的优点。
#include <stdio.h>
#include <stdlib.h>
typedef int ListItem; // 表元素类型
typedef ListItem *addr; // 表元素指针类型
#define eq(A, B) (A == B) // 元素相等
typedef struct node *link; // 表结点指针类型
typedef struct node
{
ListItem element; // 表元素
link next; // 指向下一个结点的指针域
} Node;
link NewNode() // 新建一个结点
{
return (link)malloc(sizeof(Node));
}
typedef struct llist *List; // 单链表指针
typedef struct llist // 单链表
{
link first, // 链表首指针
curr, // 当前结点指针
last; // 表尾指针
} Llist;
List ListInit(); // 表结构初始化,返回一个结构体指针
int ListEmpty(List L); // 测试表是否为空
int ListLength(List L); // 表L的长度
ListItem ListRetrieve(int k, List L); // 返回表L位置k的元素
int ListLocate(ListItem x, List L); // 元素x在表L的位置
void ListInsert(int k, ListItem x, List L); // 在表L索引k的位置插入元素x
ListItem ListDelete(int k, List L); //从表L中删除位置k的元素
void PrintList(List L); // 按照位置次序输出表L中的元素
void ItemShow(ListItem x); // 输出表元素
int main(int argc, char const *argv[])
{
List L = ListInit();
puts("Init success.");
link node_1 = NewNode();
link node_2 = NewNode();
link node_3 = NewNode();
node_1->element = 11;
node_2->element = 22;
node_3->element = 33;
L->first = node_1;
node_1->next = node_2;
node_2->next = node_3;
node_3->next = 0;
printf("list length is %d.\n", ListLength(L));
PrintList(L);
puts("---------------------");
printf("22 locate is %d.\n", ListLocate(22, L));
puts("---------------------");
ListInsert(2, 44, L);
puts("after ListInsert(2, 44, L); ");
PrintList(L);
puts("---------------------");
ListItem delete_num = ListDelete(4, L);
puts("after ListDelete(4, L) ");
PrintList(L);
puts("---------------------");
free(L);
puts("free success.");
return 0;
}
void ItemShow(ListItem x) // 输出表元素
{
printf("%d \n", x);
}
List ListInit() // 单链表结构初始化,返回一个结构体指针
{
List L = (List)malloc(sizeof *L);
L->first = 0;
return L;
}
int ListEmpty(List L) // 测试表是否为空
{
return L->first == 0;
}
int ListLength(List L) // 遍历链表所有元素计算长度
{
int len = 0; // 记录表长度,作为返回
link p = L->first; // p为链表首结点
while (p)
{
len++;
p = p->next;
}
return len;
}
ListItem ListRetrieve(int k, List L) // 返回表L位置k的结点的值
{
if (k < 1)
return 0;
link p = L->first;
int i = 1; // 从1开始遍历链表
while (i < k && p)
{
p = p->next;
i++;
}
return p->element;
}
int ListLocate(ListItem x, List L) // 结点x在表L的位置
{
int i = 1;
link p = L->first;
while (p && p->element != x)
{
p = p->next;
i++;
}
return p ? i : 0; // 若结点值存在返回其位置i,不存在返回0
}
void ListInsert(int k, ListItem x, List L) // 在表L索引k的位置插入结点值为x的结点
{
if (k < 0)
return;
link p = L->first;
for (int i = 1; i < k && p; i++) // 先遍历到位置k
p = p->next;
link y = NewNode(); // 新建一个结点,赋值为x
y->element = x;
if (k) // 若位置k存在,将y的next指向k的next;位置k的next指向y
{
y->next = p->next;
p->next = y;
}
else // 遍历不到,就添加到表头
{
y->next = L->first;
L->first = y;
}
}
ListItem ListDelete(int k, List L) //从表L中删除位置k的元素
{
if (k < 1 || !L->first) // 删除不合法
return 0;
link p = L->first; // 表头结点 p
if (k == 1) // 删除表头,
L->first = p->next;
else // 删除表中间
{
link q = L->first; // p q 两个都是表头结点,p是辅助的,q用来删除结点,删除相当于直接跳过这个结点,将next指针指向下下个结点
for (int i = 1; i < k - 1 && q; i++) // 先遍历到k
q = q->next;
p = q->next;
q->next = p->next;
}
ListItem x = p->element; // 用作返回的被删除结点的值
free(p);
return x;
}
void PrintList(List L) // 按照位置次序输出表L中的元素
{
for (link p = L->first; p; p = p->next)
{
ItemShow(p->element);
}
}
result:
Init success.
list length is 3.
11
22
33
---------------------
22 locate is 2.
---------------------
after ListInsert(2, 44, L);
11
22
44
33
---------------------
after ListDelete(4, L)
11
22
44
---------------------
free success.