数据结构-链表(C语言)

数据结构:

程序 = 数据结构 + 算法
数据结构是计算机存储、组织数据的方式。

根据数据元素之间的关系,通常有如下四类基本结构:

(1) 集合
结构中的数据元素之间,除了"同属于一个集合"外,
别无其他的关系。

(2) 线性结构
数据元素之间的关系是线性关系。

(3) 树形结构
数据元素之间关系是树状(层次)

(4) 网状结构(图)

线性结构:
线性表"中的数据元素可以是各式各样的类型,但是在同一个线性表中,数据元素必须是同一类型。并且相邻的数据元素之间存在着序偶(顺序)关系。
若将线性表记为: (a1, a2, a3, …, an)

(1) 存在着唯一一个被称为"第一个"的数据元素。
(2) 存在着唯一一个被称为"最后一个"的数据元素。
(3) 除"第一个"元素外,集合中的每个数据元素有且仅有一个前驱数据元素。
(4) 除"最后一个"元素外,集合中的每个数据元素有且仅有一个后继数据元素。

顺序结构 => “数组”
线性表的顺序表示是指 用一组地址连续的存储单元依次存储‘线性表中的数据元素。
我们知道计算机储存空间是有限的,不能提供一段很大连续的存储空间,数据也不能无限的被存储。

链式结构=> “链表”
保存每个数据元素时,不必用连续的存储空间。
数据元素的存储单元不是连续的。
但是在保存每个数据元素的同时,额外开辟一个指针大小的内存空间,
来保存它(数据元素)逻辑上的 上一个数据元素 或 下一个数据元素 或
同时保存上下两个数据元素。

单链表

在这里插入图片描述

扫描二维码关注公众号,回复: 14673647 查看本文章
数据的类型: 
		typedef int ElemType;
	
	数据节点类型: 
		struct node
		{
    
    
			  ElemType data; //数据域

			  struct node * next; //指针域
		};

根据用户的输入去创建一个有序链表

struct node* Create_Order(void)
{
    
    
	ElemType date;
	struct node * first = NULL;//指向第一个数据节点的指针
	struct node * p = NULL;//指向代添加的那个数据节点

	while (1)
	{
    
    
		scanf("%d", &date);

		if (date == 0)//输入为0就结束
		{
    
    
			break;
		}
		
		//开辟空间 保存数据
		p = (struct node*)malloc(sizeof(struct node));
		p->data = date;
		p->next = NULL;

		//插入函数,使链表有序
		first = insert_node(first,p);
	}
	return first;
}


//有序插入函数
struct node* insert_node(struct node* first, struct node* p)
{
    
    
	if (first == NULL)
	{
    
    
		return p;

	}
	if (p == NULL)
	{
    
    
		return first;
	}
	//找插入位置
	struct node* pk = NULL;
	struct node* pr = NULL;
	pk = first;
	while (pk)
	{
    
    
		if (pk->data > p->data)
		{
    
    
			break;
		}
		else {
    
    
			pr = pk;
			pk = pk->next;
		}
	}
	
	//插入操作
	if (pk == NULL)
	{
    
    
		pr->next=p;
	}
	else if (pk == first)
	{
    
    
		p->next = first;
		first = p;
	}
	else
	{
    
    
		 pr->next=p;
		 p->next = pk;
	}

	return first;
}

带头结点的单链表

很多时候,我们需要经常用到单链表中的结点的个数,并且还可能需要用到单链表的最后一个结点指针。
所以用带头结点的链表,就可以轻松解决这些问题。
在这里插入图片描述

数据结点中的数据域类型: 
	typedef int ElemType;
	
	数据结点的类型: 
	typedef struct node 
	{
    
    
		ElemType data; //数据域 
		struct node * next;
	}Node;
	
	头结点数据类型: 
	typedef struct head_node
	{
    
    
		struct node * first;
		int num;
		struct node * last;
	}Head;

根据用户的输入去创建一个有序链表

//创建一个无序链表
Head* Create_Head(void)
{
    
    
	Head* h = (Head*)malloc(sizeof(Head)); //开辟头节点空间
	h->first = NULL;
	h->last = NULL;
	h->num = 0;

	Node* p = NULL;
	ElemType d;

	while (1)
	{
    
    
		scanf("%d", &d);
		if (d==0)
		{
    
    
			break;
		}

		p = (Node*)malloc(sizeof(Node));
		p->data = d;
		p->next = NULL;

		Insert_Node(h, p);//调用有序插入函数
	}
	return h; //返回头结点
}

//有序插入
 void Insert_Node(Head* h, Node* p)
 {
    
    
	 if (h == NULL || p == NULL)
	 {
    
    
		 return;
	 }
	 if (h->num == 0)
	 {
    
    
		 h->first = p;
		 h->last = p;
	 }
	 else
	 {
    
    
		 Node* pr = NULL;
		 Node* pk = h->first;

		 while (pk)
		 {
    
    
			 if (pk->data > p->data)
			 {
    
    
				 break;
			 }
			 else
			 {
    
    
				 pr = pk;
				 pk = pk->next;
			 }
		 }

		 if (pk == NULL)//尾插
		 {
    
    
			 h->last->next = p;
			 h->last = p;

		 }
		 else if (pk == h->first)//头插
		 {
    
    
			 p->next = h->first;
			 h->first = p;

		 }
		 else//中插
		 {
    
    
			 pr->next = p;
			 p->next = pk;

		 }
		
	 } 
	 h->num++;
 }

双向链表

单链表只有一个方向 next next …
在单链表上删除一个节点px,必须要找到px前面的那个节点,那能不能轻松的直接找到px的前面的节点。---- 双向链表

一个结点既要保存它的前面和后面的结点指针
在这里插入图片描述

typedef int ElemType;
		
		//数据结点的类型
		typedef struct biNode
		{
    
    
			ElemType data;
			
			struct biNode *next; //下个节点
			struct biNode *ago; //上个节点

		}Node;
		
		typedef struct biLinkedlist
		{
    
    
			struct biNode * first; 
			struct biNode * last;
			int num ;
		}Head;

根据用户的输入去创建一个有序链表

//创建无序链表
Head* Create_Head(void)
{
    
    
	Head* h = (Head*)malloc(sizeof(Head));
	h->first = NULL;
	h->last = NULL;
	h->num = 0;

	Node* p = NULL;
	ElemType data;

	while (1)
	{
    
    
		scanf("%d", &data);
		if (data==0)
		{
    
    
			break;
		}
		p = (Node*)malloc(sizeof(Node));
		p->data = data;
		p->next = NULL;
		p->ago = NULL;

		Insert_Node(h, p);
	}
	return h;
}

//有序插入
void Insert_Node(Head* h, Node* p)
{
    
    
	if (h==NULL || p==NULL)
	{
    
    
		return;
	}

	if(h->num==0)//p为第一个节点
	{
    
     
		h->first = p;
		h->last = p;
	}
	else
	{
    
    
		Node* pk = h->first;
		while (pk)//找位置
		{
    
    
			if (pk->data > p->data)
			{
    
    
				break;
			}
			
			pk = pk->next;
		}
		if (pk == h->first)//头插
		{
    
    
			p->next = h->first;

			h->first->ago = p;

			h->first = p;
		}
		else if (pk == NULL)//尾插
		{
    
    
			
			h->last->next = p;
			
			
			p->ago = h->last;
			
			
			h->last = p;
		}
		else//中插
		{
    
    
			pk->ago->next = p;
			p->ago = pk->ago;
			p->next = pk;
			pk->ago = p;
		}
	}
	h->num++;
}

双向循环链表(单向循环链表)

如果遍历到最后一个结点,要返回第一个结点,
可能需要回到前面,再遍历一次,因为最后一个结点的next域为NULL.
能不能将最后一个结点的指针指向第一个结点?

单向循环链表
最后一个结点的next域,指向第一个结点

双向循环链表
最后一个结点的next域,指向第一个结点
第一个结点的prev域,指向最后一个结点

//数据域类型 
		typedef int Elemtype; 
		
		//数据结点的类型 
		typedef struct biNode
		{
    
    
			//数据域
			Elemtype data; 
			
			//指针域 
			struct biNode * next; 
			struct biNode * ago;
		}Node;
		
		
		//头结点的类型 
		typedef struct biHead 
		{
    
    
			//指向第一个数据结点指针 
			biNode * first;
			
			//指向最后一个数据结点指针 
			biNode * last; 
			
			//数据结点的个数 
			//int num;
		}Head;

根据用户的输入去创建一个有序链表

Head* Create_Head(void)
{
    
    
	Head* h = (Head*)malloc(sizeof(Head*));
	h->first = NULL;
	h->last = NULL;
	h->num = 0;

	Node* p = NULL;
	ElemType data;

	while (1)
	{
    
    
		scanf("%d", &data);
		if (data == 0)
		{
    
    
			break;
		}
		p = (Node*)malloc(sizeof(Node));
		p->data = data;
		p->next = NULL;
		p->ago = NULL;
		
		Insert_Node(h, p);

	}
	return h;
}


void Insert_Node(Head* h, Node* p)
{
    
    
	if (h==NULL || p==NULL)
	{
    
    
		return;
	}
	if (h->num==0)
	{
    
    
		h->first = p;
		h->last = p;
		p->ago = p;
		p->next = p;
	}
	else
	{
    
    
		Node* pk = h->first;
		Node* pr = NULL;
		while (pk!=pr)
		{
    
    
			if (pk->data > p->data )
			{
    
    
				break;
			}
			else
			{
    
    
				pr = h->first;
				pk = pk->next;
			}
			
		}
			if (pk==h->first && pr == NULL)
			{
    
    
				p->next = h->first;
				h->first->ago = p;
				h->last->next = p;
				h->first = p;
				h->first->ago = h->last;
			}
			else if (pk==pr)
			{
    
    
				h->last->next = p;
				p->ago = h->last;
				h->first->ago = p;
				h->last = p;

				h->last->next = h->first;
			}
			else
			{
    
    
				pk->ago->next = p;

				p->ago = pk->ago;

				p->next = pk;
				pk->ago = p;
			}
		}
	h->num++;
}

猜你喜欢

转载自blog.csdn.net/weixin_46836491/article/details/125943371
今日推荐