单链表


声明一个指向自身的结构体
错误写法:

struct Test
{
        int x;
        int y;
        struct Test test;
};

正确写法:

struct Test
{
        int x;
        int y;
        struct Test *test;
};

单链表

单链表是最简单的一种链表实现方式,它包含两个域,
一个信息域和一个指针域:
在这里插入图片描述
真正的单链表它还需要一个头指针,用于存放指向链表第一个节点的地址:
在这里插入图片描述

单链表节点声明

#include <stdio.h>

struct Book
{
	char title[128];
	char author[40];
	struct Book *next;
};
 
 int main(void)
 {
 	return 0;
 }

单链表中插入元素

头插法

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

struct Book
{
	char title[128];
	char author[40];
	struct Book *next;
};
 
void getInput(struct Book *book)
{
	printf("请输入书名:");
	scanf("%s",book->title);
	printf("请输入作者:");
	scanf("%s",book->author);
 } 
void addBook(struct Book **library)
{
	struct Book *book,*temp;
	
	book = (struct Book *)malloc(sizeof(struct Book));
	if (book = NULL)
	{
		printf("内存分配失败!\n");
		exit(1);
	}
	getInput(book);
	
	if(*library != NULL)
	{
		temp = *library;
		*library = book;
		book->next = temp;
	}
	else
	{
		*library = book;
		book->next = NULL;
	}
		
}

void printLibrary(struct Book *library)
{
	struct Book *book;
	int count = 1;
	
	book = library;
	while(book != NULL)
	{
		printf("Book%d:",count);
		printf("书名:%s",book->title);
		printf("作者:%s",book->author);
		book = book->next;
		count++; 
	}
}

void releaseLibrary(struct Book *library)
{
	while(library != NULL)
	{
		free(library);
		library = library->next;
	}
}
 
 int main(void)
 {
 	struct Book *library = NULL;
 	int ch;
 	
 	while(1)
 	{
 		printf("请问是否需要录入书籍信息(Y/N):");
 		do
 		{
 				ch = getchar();		
		 }while(ch != 'Y'&& ch !='N');
		 
		 if(ch == 'Y')
		 {
		 	addBook(&library);
		 	
		 }
		 else
		 {
		 	break;
		 }
	 }
 	
 	printf("请问是否需要打印书籍信息(Y/N):");
 	do
 	{
 			ch = getchar();		
	}while(ch != 'Y'&& ch !='N');
 	
 	if(ch == 'Y')
	 {
	 	printLibrary(library);
	  } 
	  
	  releaseLibrary(library);
 	
 	addBook(&library);
 	
 	return 0;
 }

尾插法

将数据插入到单链表的尾部位置。
在这里插入图片描述

...
void addBook(struct Book **library)
{
        struct Book *book;
        static struct Book *tail;

        book = (struct Book *)malloc(sizeof(struct Book));
        if (book == NULL)
        {
                printf("内存分配失败!\n");
                exit(1);
        }

        getInput(book);

        if (*library != NULL)
        {
                tail->next = book;
                book->next = NULL;
        }
        else
        {
                *library = book;
                book->next = NULL;
        }

        tail = book;
}

搜索单链表

struct Book *searchBook(struct Book *library, char *target)
{
        struct Book *book;

        book = library;
        while (book != NULL)
        {
                if (!strcmp(book->title, target) || !strcmp(book->author, target))
                {
                        break;
                }
                book = book->next;
        }

        return book;
}

void printBook(struct Book *book)
{
        printf("书名:%s\n", book->title);
        printf("作者:%s\n", book->author);
}
...
int main(void)
{
        ...
        printf("\n请输入书名或作者:");
        scanf("%s", input);

        book = searchBook(library, input);
        if (book == NULL)
        {
                printf("很抱歉,没能找到!\n");
        }
        else
        {
                do
                {
                        printf("已找到符合条件的书籍...\n");
                        printBook(book);
                } while ((book = searchBook(book->next, input)) != NULL);
        }

        releaseLibrary(&library);

        return 0;
}

插入节点到指定的位置

  • 单链表和数组相比较的话,最大的优势就是插入元素到指定位置的效率。

  • 对于数组来说,插入一个元素到指定的位置,需要将其后面所有的元素都依次移动一次,效率低

  • 相比之下,单链表的效率就要高很多了。因为对于单链表来说,只需要改动一下指针即可。

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

struct Node
{
        int value;
        struct Node *next;
};

void insertNode(struct Node **head, int value)
{
        struct Node *previous;//前一个节点位置 
        struct Node *current;//当前节点位置 
        struct Node *new;//新插入节点位置 

        current = *head;
        previous = NULL;

        while (current != NULL && current->value < value)
        {
                previous = current;
                current = current->next;
        }

        new = (struct Node *)malloc(sizeof(struct Node));
        if (new == NULL)
        {
                printf("内存分配失败!\n");
                exit(1);
        }
        new->value = value;
        new->next = current;

        if (previous == NULL)
        {
                *head = new;
        }
        else
        {
                previous->next = new;
        }
}

void printNode(struct Node *head)
{
        struct Node *current;

        current = head;
        while (current != NULL)
        {
                printf("%d ", current->value);
                current = current->next;
        }

        putchar('\n');
}

int main(void)
{
        struct Node *head = NULL;
        int input;

        printf("开始测试插入整数...\n");
        while (1)
        {
                printf("请输入一个整数(输入-1表示结束):");
                scanf("%d", &input);
                if (input == -1)
                {
                        break;
                }
                insertNode(&head, input);
                printNode(head);
        }
        
        return 0;
}
while (current != NULL && current->value < value)
{
        previous = current;
        current = current->next;
}

while 函数用于找到符合条件的链表节点,也就是在有序的链表中找到比传入的value更大的值,然后停下来;如果没有,则在链表的尾部位置停止(current == NULL 时结束循环)。

由于单链表一旦指向下一个节点,就没办法回头了,所以我们使用 previous 变量来记录 current 节点的上一个节点。
在这里插入图片描述

单链表中删除元素

删除某个节点的数据,其实也是修改指针的事儿,两个步骤搞定:

修改待删除节点的上一个节点的指针,将其指向待删除节点的下一个节点
释放待删除节点的内存空间

在这里插入图片描述

...
void deleteNode(struct Node **head, int value)
{
        struct Node *previous;
        struct Node *current;

        current = *head;
        previous = NULL;

        while (current != NULL && current->value != value)
        {
                previous = current;
                current = current->next;
        }

        if (current == NULL)
        {
                printf("找不到匹配的节点!\n");
                return ;
        }
        else
        {
                if (previous == NULL)
                {
                        *head = current->next;
                }
                else
                {
                        previous->next = current->next;
                }
                free(current);
        }
}
...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值