数据结构:单链表

数据结构:单链表

链表是一种常见的数据结构,它用于存储一系列物品,并通过指针链接它们。在C语言中,链表通常由一个结构体指针表示,称为节点。节点包含了一个指向下一个节点的指针,从而形成了一个链表。

链表的定义

先来定义链表的结构体,在C语言中定义节点的结构体如下:

typedef struct Node {
  int data;           // 存储的数据
  struct Node *next;  // 下一个节点的指针
} Node;

第一个字段是用于存储数据的变量,在本例中我们定义它为int类型。第二个字段是一个指针,指向下一个节点。

链表的用法

链表可以用于存储大量的数据,例如在一个数据集中,可以通过链表连接每个数据项。如果数据集大小不确定或必须动态地增长或缩小,链表就成为了一种理想的数据结构。

链表的操作

链表的操作包括插入、删除、查找等。在下面的示例中,我们将实现一个简单的链表操作程序。

  1. 插入操作

要向链表中插入一个节点,可以先创建一个新节点,并将它的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;
}
  1. 删除操作

要从链表中删除一个节点,必须知道要删除节点的前一个节点。找到前一个节点后,只需要更新它的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;
}
  1. 查找操作

要查找一个节点,只需要从链表的第一个节点开始向后移动,查找和目标值相等的节点。

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语言中通过指针连接每个元素,形成链表。链表的操作包括插入、删除、查找等,它可以有效地存储大量的动态数据。同时,为了避免内存泄漏,使用链表时需要注意内存管理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值