数据结构:单链表
链表是一种常见的数据结构,它用于存储一系列物品,并通过指针链接它们。在C语言中,链表通常由一个结构体指针表示,称为节点。节点包含了一个指向下一个节点的指针,从而形成了一个链表。
链表的定义
先来定义链表的结构体,在C语言中定义节点的结构体如下:
typedef struct Node {
int data; // 存储的数据
struct Node *next; // 下一个节点的指针
} Node;
第一个字段是用于存储数据的变量,在本例中我们定义它为int类型。第二个字段是一个指针,指向下一个节点。
链表的用法
链表可以用于存储大量的数据,例如在一个数据集中,可以通过链表连接每个数据项。如果数据集大小不确定或必须动态地增长或缩小,链表就成为了一种理想的数据结构。
链表的操作
链表的操作包括插入、删除、查找等。在下面的示例中,我们将实现一个简单的链表操作程序。
- 插入操作
要向链表中插入一个节点,可以先创建一个新节点,并将它的next指针指向当前节点的下一个节点(如果有)。然后将当前节点的next指针指向新节点。
Node *insert(Node *current, int data) {
Node *new_node = (Node*)malloc(sizeof(Node)); // 创建一个新节点
new_node->data = data; // 保存数据
if (current == NULL) { // 如果链表是空的,则新节点为链表的第一个节点
new_node->next = NULL;
return new_node;
}
// 将新节点的下一个节点指向当前节点的下一个节点
new_node->next = current->next;
// 将当前节点的下一个节点指向新节点
current->next = new_node;
return current;
}
- 删除操作
要从链表中删除一个节点,必须知道要删除节点的前一个节点。找到前一个节点后,只需要更新它的next指针即可。
Node *delete(Node *current, int data) {
Node *tmp;
if (current == NULL) { // 如果链表为空,返回NULL
return NULL;
}
if (current->data == data) { // 找到了要删除的节点
tmp = current->next;
free(current); // 释放内存
return tmp;
}
// 递归进行查找
current->next = delete(current->next, data);
return current;
}
- 查找操作
要查找一个节点,只需要从链表的第一个节点开始向后移动,查找和目标值相等的节点。
Node *find(Node *head, int data) {
if (head == NULL) {
return NULL;
}
if (head->data == data) {
return head;
} else {
return find(head->next, data);
}
}
链表的案例
现在我们用链表来解决一个问题:合并两个有序的链表。我们将创建一个新链表,并将两个链表的元素按照升序插入到新链表中。
Node *mergeLists(Node *list1, Node *list2) {
Node dummy_head;
Node *tail = &dummy_head;
while (1) {
if (list1 == NULL) { // 第一个链表已经为空,将第二个链表剩余的节点添加到新链表末尾
tail->next = list2;
break;
}
if (list2 == NULL) { // 第二个链表已经为空,将第一个链表剩余的节点添加到新链表末尾
tail->next = list1;
break;
}
// 从两个链表中找到较小的节点,并将其添加到新链表末尾
if (list1->data <= list2->data) {
tail->next = list1;
list1 = list1->next;
} else {
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
// 返回新链表的头部节点
return dummy_head.next;
}
综合链表的操作:动态增删改查
下面通过自己写的案列,利用头插法动态创建链表,实现增删改查。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
}Node;
//头插法
Node *headInsert(Node *head,Node *new)
{
Node *p = head;
if(p == NULL){
head = new;
return head;
}
else{
new->next = head;
head = new;
}
return head;
}
//动态创建链表
Node *createLink(Node *head)
{
Node *new;
printf("===========================================================\n");
printf("Start your creation!If you want to stop it,just input '000'!\n");
printf("===========================================================\n");
while(1){
new = (Node *)malloc(sizeof(Node));
new->next = NULL;
printf("Please input the data you want:");
scanf("%d",&(new->data));
if(new->data == 000){
free(new);
return head;
}
head = headInsert(head,new);
}
}
//链表节点
int numOfNode(Node *head)
{
int num = 0;
Node *p;
p = head;
while(p != NULL){
num++;
p = p->next;
}
return num;
}
//删除链表
Node *deleteNode(Node *head,int data)
{
Node *p;
p = head;
if(p->data == data){
head = head->next;
return head;
}
while(p->next != NULL){
if(p->next->data == data){
p->next = p->next->next;
return head;
}
p = p->next;
}
return head;
}
//修改节点
Node *updateNode(Node *head,int data,int newData)
{
Node *p;
p = head;
//先找到这个数,再改!
while(p != NULL){
if(p->data == data){
p->data = newData;
}
p = p->next;
}
return head;
}
//翻转链表
Node *ReverseList(Node *head )
{
int a[10000];
int i=0;
Node *p=head;
while(p != NULL)
{
a[i]=p->data;
i++;
p=p->next;
}
p=head;
i--;
while(p != NULL)
{
p->data=a[i];
i--;
p=p->next;
}
return head;
}
//查找链表节点
Node *searchNode(Node *head,int data)
{
Node *p;
p = head;
//找到这个数
while(p != NULL){
if(p->data = data){
printf("查找成功!\n");
break;
}else{
printf("查找失败!\n");
}
p = p->next;
}
return head;
}
//将链表快速排序
void quicksort(Node *head, Node *tail){
if(head != tail) {
int key = head->data;
Node *p = head;
Node *q = head->next;
while(q != tail){
if(q->data < key) {
p = p->next;
int tmp = p->data;
p->data = q->data;
q->data = tmp;
}
q = q->next;
}
head->data = p->data;
p->data = key;
quicksort(head, p);
quicksort(p->next, tail);
}
}
Node* sortInList(Node* head) {
quicksort(head, NULL);
return head;
}
//打印链表
void printLink(Node *head)
{
Node *p;
p = head;
while(p != NULL){
printf("%d ",p->data);
p = p->next;
}
putchar('\n');
}
int main()
{
Node *head = NULL;
int sum;
int data;
int newData;
int cmd;
head = createLink(head);
printf("=============头插法创建============\n");
printLink(head);
head = sortInList(head);
printf("排序:\n");
printLink(head);
head = ReverseList(head);
printf("翻转:\n");
printLink(head);
sum = numOfNode(head);
printf("Sum:%-3d\n",sum);
printf("================================\n");
printf("输入你想删除的数字:");
scanf("%d",&data);
head = deleteNode(head,data);
printf("删除后:");
printLink(head);
sum = numOfNode(head);
printf("Sum:%-3d\n",sum);
printf("================================\n");
printf("输入你想修改的数字:");
scanf("%d",&data);
printf("输入你想修改后的数字:");
scanf("%d",&newData);
head = updateNode(head,data,newData);
printf("修改后:");
printLink(head);
sum = numOfNode(head);
printf("Sum:%-3d\n",sum);
printf("================================\n");
printf("输入你想查找的数字:");
scanf("%d",&data);
head = searchNode(head,data);
printf("================================\n");
return 0;
}
链表的注意事项
链表的主要优点是它能够动态地添加或删除元素,但它也需要更多的内存和处理时间。此外,链表的节点没有顺序,因此难以进行随机访问。在使用链表时,需要注意内存管理,避免内存泄露。
总结
链表是一种常见的数据结构,在C语言中通过指针连接每个元素,形成链表。链表的操作包括插入、删除、查找等,它可以有效地存储大量的动态数据。同时,为了避免内存泄漏,使用链表时需要注意内存管理。