本文介绍C语言中结构体指针的应用,使用结构体指针来构建单链表和双链表,以及实现一些关于链表的操作接口。
单链表
链表(linked list)就 一些包含数据的独立数据结构(通常称为节点)的集合。链表中的每个节点通过链 或指针连接在一起。程序通过指针访问链表中的节点。通常节点是动态分配的,但 有时你也能看到由节点数组构建的链表。即使在这种情况下,程序也是通过指针来 遍历链表的。
在单链表中,每个节点包含一个指向链表下一节点的指针。
链表最后一个节点 的指针字段的值为NULL,提示链表后面不再有其他节点。在你找到链表的第1个节点 后,指针就可以带你访问剩余的所有节点。
为了记住链表的起始位置,可以使用一 个根指针(root pointer)。根指针指向链表的第1个节点。注意根指针只是一个指 针,它不包含任何数据。
链表由一个个节点生成。下面就需要声明一个节点:
typedef struct Node
{
struct Node* next;
int data;
}Listnode, *nodep;
有关于结构体的声明,上一节已经做了详细介绍。
这里利用typedef给节点的结构体取了别名 :Listnode;
给指向节点的结构体指针取了别名 nodep;
存储于每个节点的数据是一个整型值。这个链表包含三个节点。如果你从根指 针开始,随着指针到达第1个节点,你可以访问存储于那个节点的数据。随着第1个 节点的指针可以到达第2个节点,你可以访问存储在那里的数据。最后,第2个节点 的指针带你来到最后一个节点。零值提示它是一个NULL指针,在这里它表示链表中 不再有更多的节点。
创建根节点:
nodep Linklsit_Creat(void)
{
nodep temp = NULL;
temp = (nodep)malloc(sizeof(Listnode));
if (temp == NULL)
return NULL;
temp->data = 0;
temp->next = NULL;
return temp;
}
根节点不存储内容,他指向存储数据的第一个节点,根节点也可以叫头结点。
添加新节点:
在尾部添加新节点:
int LinkList_Add_Tail(nodep root, int val)
{
if (root == NULL) return -1;
nodep cur = root;
while (cur->next != NULL)cur = cur->next;
nodep new = (nodep)malloc(sizeof(Listnode));
if (new == NULL) return 0;
new->data = val;
new->next = NULL;
cur->next = new;
return 1;
}
该函数接受两个参数,一个是根节点的指针,一个是新节点储存的数据。
返回值是错误码。
在头部添加新节点:
int LinkList_Add_Head(nodep root, int val)
{
if (root == NULL) return -1;
nodep new = (nodep)malloc(sizeof(Listnode));
if (new == NULL)return 0;
new->data = val;
new->next = root->next;
root->next = new;
return 1;
}
该函数接受两个参数,一个是根节点的指针,一个是新节点储存的数据。
在根节点和第一个节点之前添加一个新节点,使之成为新的第一个节点。
在指定位置添加新节点:、
int LinkList_Add_Index(nodep root, int index,int val)
{
if (root == NULL) return -1;
if (index == 0) LinkList_Add_Head(root, val);
nodep cur = root->next;
nodep new = (nodep)malloc(sizeof(Listnode));
if (new == NULL) return -1;
for (int i = 1; cur != NULL; i++)
{
if (i == index)
{
new->data = val;
new->next = cur->next;
cur->next = new;
return 1;
}
else cur = cur->next;
}
return 0;
}
在有序链表中插入一个新值,让其仍旧有序。
/*
** 插入到一个有序单链表。函数的参数是一个指向链表第一个节点的指针,以及一个需要插入的新值
*/
int Linklist_Insert(register nodep* rootp, int val)
{
if (*rootp == NULL)return -1;
nodep cur;
nodep new;
while ((cur = *rootp) != NULL && val > cur->data)
{
rootp = &cur->next;
}
new = (nodep)malloc(sizeof(Listnode));
if (new == NULL) return 0;
new->data = val;
new->next = cur;
*rootp = new;
return 1;
}
移除节点:
方法一:
int Linklist_Remove_Node(nodep* rootp, nodep node)
{
if (*rootp == NULL || node == NULL) return -1;
nodep cur = *rootp;
while ((cur = *rootp) != NULL && cur != node)
{
rootp = &cur->next;
}
*rootp = node->next;
free(node);
return 0;
}
方法二:
int LinkList_Del_Index(nodep root, int index)
{
if (root == NULL) return -1;
if (index == 0 )
{
nodep temp = root->next;
if (temp != NULL)
{
root->next = temp->next;
free(temp);
return 1;
}
}
nodep cur = root->next;
for (int i = 1; cur != NULL && cur->next != NULL; i++)
{
if (i == index)
{
nodep temp = cur->next;
if (temp != NULL)
{
cur->next = temp->next;
free(temp);
return 1;
}
}
else cur = cur->next;
}
return 0;
}
计算节点数:
/*计数一个单链表的节点个数*/
int Linklist_NodeLength(nodep root)
{
if (root == NULL) return -1;
int length = 1;
nodep cur = root->next;
while ((cur=cur->next) != NULL)length++;
return length ;
}
查找给定值:
/*在一个无序的单链表中寻找一个特定的值,并返回一个指
向该节点的指针。*/
nodep Linklist_Find_Val(nodep root, int val)
{
if (root == NULL) return NULL;
nodep cur = root->next;
while (cur != NULL)
{
if(cur->data == val)
return cur;
else
cur = cur->next;
}
return NULL;
}
翻转链表:
/*翻转链表,当链表被重排之后,函数返回一个指向链表
新头节点的指针*/
nodep Linklist_Reverse(nodep root)
{
nodep temp;
nodep pre = NULL;
nodep cur = root;
while (cur != NULL)
{
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
打印链表:
/*打印单链表*/
void Linklist_Show(nodep root)
{
nodep cur = root;
if (root == NULL || cur == NULL)printf("list is null\n");
for (int i = 0; cur != NULL; i++)
{
printf("%d -> ",cur->data);
cur = cur->next;
}
printf("NULL\n");
}
以上就是单链表常见函数的实现。