C语言单链表和双链表基础(增、删、查找)

一.单链表

#include <stdio.h>

#include <stdlib.h>



struct node
{
	unsigned char elem;
	struct node *next;
};

void create_list(unsigned char elem);
void insert_node(int pos, unsigned char elem);
void delete_node(int pos);
void print_linklist(void);
int search(unsigned char elem);


struct node *head = NULL;
struct node *tail = NULL;




int main(void)
{
	create_list('A');
	create_list('B');
	create_list('C');
	create_list('D');
	print_linklist();

	delete_node(0);
	print_linklist();

	insert_node(0, 'F');
	insert_node(2, 'Z');
	print_linklist();

	if(search('C'))
		printf("the elem is found in the linklist\n");
	else
		printf("Can not find it\n");

	return 0;
}


//这里插入采用的尾插入
void create_list(unsigned char elem)
{
	struct node *p = (struct node *)malloc(sizeof(struct node)); //开辟struct node 大小的内存,让 p指针指向它
	p->elem = elem;//对开辟的结构体数据部分进行元素的填充
	p->next = NULL;//指针部分进行填充,让它指向0地址处

	if(head == NULL) //初始化我们的头指针
		head = p; //让头指针指向我们申请的第一个节点的地址
	else
		tail->next = p; //p节点的指针域指向我们malloc分配的新节点的地址

	tail = p; //指针永远指向最后一个节点,然后它的p节点的指针域(tail->next),就可以指向我们新来的节点p
}

/*插入节点的实现思路:
 比如现在1 2 3 4 5,我们要在3前面插入6,我们就要找到3的前一个节点,也就是2
 让2的指针域指向6的地址,6的指针域指向3,那么我们需要遍历链表

*/
void insert_node(int pos, unsigned char elem)
{
	struct node *pre;
	pre = head;
	int i = 0; 
	struct node *p = (struct node *)malloc(sizeof(struct node)); //开辟空间存放新的节点

	if(pos == 0)  //在头节点的地方插入
	{
		p->elem = elem; 
		p->next = head;//头指针head里面存的是第一个节点的地址,把它给我们新插入节点的指针域,
                     //让新插入元素的指针域,指向我们第一个节点
		head = p; //把我们新插入的节点的地址给头指针,让头指针指向我们的新插入的节点
	}
	else
	{
		while(i < pos - 1)   //你要找元素的位置,比你要找的元素位置少遍历1次
		{
			pre = pre->next;  //找节点的过程就是更新pre指针的指向
			i++;
		}

		p->elem = elem;
		p->next = pre->next;//p->next指向我们的pre指针域的指向的节点
		pre->next = p;  //找到的元素的指针域指向我们的p节点

		if(p->next == NULL) //在尾的地方插入
			tail = p;
	}
}

void delete_node(int pos)
{
	struct node *pre, *p;
	pre = head; //pre是我们要插入的节点的前节点
	int i = 0;

	if(pos == 0)
	{
		head = head->next;
		free(pre);
	}
	else
	{
		while(i < pos - 1)
		{
			pre = pre->next;
			i++;
		}
	
		p = pre->next;  //要删除的p节点的地址在它前节点pre的指针域
		pre->next = p->next; //让p的前节点pre的指针域指向p的后节点
		if(p->next == NULL)
			tail = pre;
		free(p);
	}
}

void print_linklist(void)
{
	struct node *p;
	
	for(p = head; p; p = p->next)
		printf("%c", p->elem);

	printf("\n");
}

int search(unsigned char elem)
{
	struct node *p;

	for(p = head; p; p = p->next)
		if(p->elem == elem)
			return 1;
	return 0;
}

代码运行如下:

ABCD
BCD
FBZCD
the elem is found in the linklist

二.双链表

为了方便理解,一定要画图,不然指针指来指去的会很懵逼

创建链表这里我们需要好好理解,每一步怎么来的,好好理解create_list函数就行,核心就是head头指针是一直指向第一个节点的,后续增加节点是通过移动tail指针,让我们的老节点的p->next = 新节点的地址,也就是tail->next。

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

struct node
{
	unsigned int elem;
	struct node *pre;
	struct node *next;
};

struct node *head = NULL;
struct node *tail = NULL;

void create_list(unsigned int elem)
{
	struct node *p = (struct node *)malloc(sizeof(struct node));
	p->elem = elem;
	p->pre = NULL;
	p->next = NULL;

	if(head == NULL) /* 指针为空,即一个节点也没有 */
		head = p;   /* 指向第一个节点 */
	else
	{
		tail->next = p; /* 让我们上个节点指向下一个节点,因为我们上个节点的next就是tail-next */
		p->pre = tail; /* 让pre指向前一个节点,因为tai = p(在下面), tail存的是pre前节点的地址 */
	}
	tail = p; /* 尾指针每次都是指向最后一个节点的 */
}

void insert_node(int pos, unsigned int elem)
{
	struct node *pre;
	pre = head;
	int i = 0;
	struct node *p = (struct node *)malloc(sizeof(struct node));

	if(pos == 0)
	{
		p->elem = elem;
		p->next = head;
		head->pre = p;
		p->pre = NULL;
		head = p;
	}
	else
	{
		while(i < pos - 1)
		{
			pre = pre->next;
			i++;
		}

		p->elem = elem;
		p->pre = pre;
		p->next = pre->next;
		if(p->next != NULL)
			pre->next->pre = p; 
		pre->next = p;

		if(p->next == NULL)
			tail = p;
	}
}

void delete_node(int pos)
{
	struct node *pre, *p;
	pre = head;
	int i = 0;

	if(pos == 0)
	{
		head = head->next;
		head->pre = NULL;
		free(pre);
	}
	else
	{
		while(i < pos - 1)
		{
			pre = pre->next;
			i++;
		}
	
		p = pre->next;
		pre->next = p->next;
		if(p->next != NULL)
			p->next->pre = pre;
		else//if(p->next == NULL)
			tail = pre;
		free(p);
	}
}

void print_linklist(void)
{
	struct node *p;
	
	for(p = head; p; p = p->next)
		printf("%5d", p->elem);

	printf("\n");
}

int search(unsigned int elem)
{
	struct node *p;

	for(p = head; p; p = p->next)
		if(p->elem == elem)
			return 1;
	return 0;
}

void reverse_print_linklist(void)
{
	struct node *p;

	for(p = tail; p; p = p->pre)
		printf("%5d", p->elem);
	printf("\n");
}

int main(void)
{
	create_list(1);
	create_list(2);
	create_list(3);
	create_list(4);
	create_list(5);
	create_list(6);
	create_list(7);
	print_linklist();

	reverse_print_linklist();

	insert_node(0, 11);
	print_linklist();

	delete_node(6);
	print_linklist();
	delete_node(0);
	print_linklist();
	delete_node(0);
	print_linklist();
	delete_node(4);
	print_linklist();
	

	insert_node(0, 8);
	print_linklist();
	insert_node(5, 9);
	print_linklist();
	insert_node(2, 13);
	print_linklist();

	return 0;
}

运行结果如下:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值