C语言之链表

什么是链表

动态进行存储分配的一种结构,可以根据需要开辟内存单元。
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表的优势就是增删非常容易。

链表图解

在这里插入图片描述
下面通过代码直接创建一个链表,一目了然。

#include <stdio.h>
#include <stdlib.h>
//链表中的一个节点.
typedef struct node
{
	int data;  //数据
	struct node* next;//指向下一个节点.
}Node,*pNode;

Node head; //初始化成0;全局变量没有初始化则保持在bss段
pNode pHead = &head;//定义头指针

//在链表的末尾添加数据.
//把DATA存入链表最后一个节点,然后把整个节点个数返回
int insert_end(int DATA)
{
	//1内存空间的申请(造车厢)
	pNode pnew = (struct node*)malloc(sizeof(Node));
	if (NULL == pnew)//内存申请失败
	{
		printf("申请失败\n");//容错处理.
		return 0;
	}
	//2.数据的初始化.(放人到车上)
	pnew->data = DATA;
	pnew->next = NULL;//链条放在地上防止静电
	
	//3连起来
	pNode ptemp = pHead;
	while (ptemp->next) //最后一个结点的next会等于NULL
	{
		ptemp = ptemp->next;//指向下一个节点
	}
	ptemp->next = pnew;//最后一个节点的next指针指向pnew,等价于把pnew链接到整个链表的末尾.

	return ++pHead->data;//头结点数据记录了整个节点个数
}

//在头结点的下一个节点添加数据.头插法.
int insert_head(int DATA)
{
	//1内存空间的申请(造车厢)
	pNode pnew = (struct node*)malloc(sizeof(Node));
	if (NULL == pnew)//内存申请失败
	{
		printf("申请失败\n");//容错处理.
		return 0;
	}
	//2.数据的初始化.(放人到车上)
	pnew->data = DATA;
	pnew->next = NULL;//链条放在地上防止静电

	//3.把新节点链接到链表
	pnew->next = pHead->next;
	 
	//4.把头结点的next指针连接到新节点
	pHead->next = pnew;
	//5.头指针数据加1. 
	return ++pHead->data;
}
//显示整个链表
void show()
{
	//1用一个临时指针指向于链表头
	pNode p = pHead;
	while (p->next)
	{
		printf("%d-> ", p->data);
		p = p->next; //p++错误
	}
	printf("%d->", p->data);
	printf("NULL\n");
}
//把链表中第一个数据为da的节点修改成DATA.
void change(int da,int DATA)
{
	pNode p = pHead;
	while (p->next)
	{
		if (p->data == da)
		{
			p->data = DATA;
			//break;如果只修改其中第一个则加上break;
		}
		p = p->next;
	}
	if (p->data == da)  //最后一个节点需要单独判断
	{
		p->data = DATA;
	}
}

//查找da数据是否在链表中存在,如果存在则返回位置.
int find(int da)
{
	int temp = 0;
	pNode p = pHead->next;  //pNode p指向头节点的下节点
	while (p->next)                  //遍历整个链表
	{
		temp++;
		if (p->data == da)         //找到了相应的数据
		{
			return temp;
		}
		p = p->next;
	}
	if (p->data == da)          //在尾部找到了对应的数据
	{
		return ++temp;
	}
	return -1;//返回错误
	
}

//主函数
int main()
{
	insert_head(10);
	insert_head(20);
	insert_head(50);
	insert_head(30);
	insert_head(50);
	insert_head(40);
	insert_head(50);
	insert_end(123);
	show();
	change(50, 666);
	printf("查找到的位置是%d\n",find(1));
	show();
	return 0;

双向链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

代码实现双向链表

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
	int data;
	struct node* prev; //当前节点的前驱节点
	struct node* next; //当前节点的后继节点
}Node,*Pnode;


//链表初始化,创建链表
/*****只可以在当前文件调用,加static
      作用: 创建一个节点,然后把节点指针返回.
      参数: 第一个:需要保存的数据.
	        第二个:当前节点的上一个节点指针
			第三个:当前节点的下一个节点指针
	  返回:创建的新的节点指针
*/
static Pnode createNode(int DATA,Pnode pr,Pnode nx)
{
	Pnode pnew = (Pnode)malloc(sizeof(Node));
	pnew->data = DATA;
	pnew->next = nx;
	pnew->prev = pr;
	return pnew;
}

typedef struct list{
	Pnode pHead;  //整个链表的头部
	Pnode pTail;  //整个链表的尾部
}List,*pList;

//初始化工作.
void init(pList ls)
{
	ls->pHead = NULL;
	ls->pTail = NULL;
}

//在末尾插入,ptail后面插.
void insert_end(pList ls,int DATA)
{
	//创建一个节点.封装到一个函数中
	// 同时把ptail移动到最后一个位置
	ls->pTail = createNode(DATA,ls->pTail,NULL);

	if (ls->pTail->prev)//有多个节点的情况
	{
	
	ls->pTail->prev->next = ls->pTail; //(难点)
	}
	else//只有一个节点的情况.
	{
		ls->pHead = ls->pTail;
	}
}

// 得到链表节点个数
int GetSize(pList ls)
{
	int size = 0;
	for (Pnode p = ls->pHead; p;p = p->next){
		++size;
	}
	return size;
}

int main()
{
	List list;
	//pList ls = mlloc;
	init(&list);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值