Linux C 数据结构—链表

一 . 链表特点/结构/分类

链表特点:
  优势:链式存储,可以很好的解决以上问题
  缺点: 一片连续的空间,成片移动的现象,数据个数固定

链表结构:
  每个数据块称之为一个节点,包含: 数据域、指针域。
  数据域: 存放数据。
  指针域: 存放下一个数据的地址。

链表分类:
  单向链表、双向链表、单向循环链表、双向循环链表。

二. 单向链表代码实现

//完整版代码

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

typedef int data_t;
typedef struct node_t
{
	data_t data;
	struct node_t * next;
}linknode_t, *linklist_t;      // linknode_t  *  等价  linklist_t

//创建空链表
linklist_t create_empty_linklist()
{
	linklist_t h = (linklist_t )malloc(sizeof(linknode_t ));//sizeof(linknode_t);求结构体的大小,不求指针的大小 
	h->next = NULL;
	return h;
}

//判断链表是否为空
int empty_linklist(linklist_t h)
{
	return  (h->next == NULL) ;    
}

//求链表长度
int length_linklist(linklist_t h)
{
	int len = 0;
	while(h->next != NULL)
	{
		len++;
		h = h->next;
	}
	return len;
}

//遍历链表
void visit_linklist(linklist_t h)
{
	h = h->next;
	while(h != NULL)
	{
		printf("%d\n",h->data);
		h = h->next;
	}
	return ;
}

//在链表中查找指定元素,返回编号。 若不存在,返回 -1.
int search_linklist(linklist_t h,data_t value)
{
	int num = 1;
	h = h->next;
	while(h != NULL)   //如果当前数据不为空,则进循环。
	{
		if(h->data == value)   //如果当前节点的数据是要查找的数据,
		{
			return num;        //那么返回对应的编号。 
		}
		h = h->next;           //if 条件为假时,才能执行到此句。 h指向下一个节点。 
		num ++;                //位置 + 1
	}
	return -1;   //while 遍历结束后,还没有执行if中的return,证明没有找到数据,返回-1,表示数据不存在。
}

//获得特定位置的值
int get_linklist(linklist_t h,int pos, data_t *val)
{
	if(pos < 1 || pos > length_linklist(h))   //大于长度的话,肯定没有数据可获取。 
	{
		return -1;
	}
	while(pos--)     //while 定位到当前要找的这个特定位置。 
		h = h->next;
	*val = h->data;    //取出当前位置的值,赋值给指针所指的变量中。 
	return 0;
}

//在链表指定位置插入元素,插入成功,返回0,失败返回 -1. 
int insert_linklist_1(linklist_t h,data_t value,int pos)
{
	if(pos < 1 || pos > length_linklist(h)+1) //可以比长度大1,证明可以插入数据到链表的最后位置上。但是再大就不行了。 
		return -1;

	while(--pos)         //定位到当前位置的前一个节点上。 
		h = h->next;

	linklist_t new = (linklist_t )malloc(sizeof(linknode_t ));  //插入节点步骤1:创建新节点。 
	new->data = value;                                          //插入节点步骤2:给新节点赋值。 
	new->next = h->next;

	h->next = new;      //插入节点步骤3:将新节点的首地址,赋值给前一个节点的next指针上。 
	return 0;
}

//按照递增的次序在链表中插入新元素
int insert_linklist_2(linklist_t h,data_t value)
{
	while(h->next != NULL)   //此 while 目的:找到 value 的插入位置。 
	{
		if(value > h->next->data)   //当前的 value 值,与 h下一个节点的数据 做比较。如果value大,继续向后。 
			h = h->next;         //也就是说,希望找到一个 value <= h->next->data 的位置,将 value 插入到 h->next->data 数据的前一个位置上。  
		else 
			break;
	}
	linklist_t new = (linklist_t )malloc(sizeof(linknode_t ));  //插入元素步骤1:创建新节点。 
	new->data = value;											//插入节点步骤2:给新节点赋值。
	new->next = h->next;

	h->next = new;      //插入节点步骤3:将新节点的首地址,赋值给前一个节点的next指针上。 
	return 0;
}

//删除链表中指定位置的元素,删除成功返回0,失败返回 -1 。 
int delete_linklist_1(linklist_t h,int pos)
{
	if(pos < 1 || pos > length_linklist(h))   //不能大于长度。 
		return -1;
		
	while(--pos)			//找到 要删除的节点 的 前一个位置。 
		h = h->next;
		
	linklist_t f = h->next;
	h->next = f->next;         //删除节点步骤1: 将后一个节点搭到前一个节点上。 
	free(f);                   //删除节点步骤2: 释放当前位置。 
	
	return 0;	
}

//删除链表中和指定值相等的所有元素。 
int delete_linklist_2(linklist_t h,data_t value)
{
	linklist_t f = NULL;
	
	while(h->next != NULL)        //找到要删除的当前位置。 
	{
		if(value == h->next->data)
		{
			f = h->next;
			h->next = f->next;   //删除节点步骤1: 将后一个节点搭到前一个节点上。 
			free(f);		     //删除节点步骤2: 释放当前位置。 
		}	
		else 
			h = h->next;
	}
	return 0;
}

//除头结点外,释放链表中其他所有节点。 
void clear_linklist(linklist_t h)
{
	if(empty_linklist(h) == 1)	   //如果链表已经为空,则不需要再释放。 
		return ;
	
	linklist_t f = NULL;

	while(h->next != NULL)    //始终释放头结点的下一个节点,直到头结点的下一个节点为空。 
	{
		f = h->next;
		h->next = f->next;   //删除节点的步骤1、 步骤2. 
		free(f);
	}
	return ;
}

//测试函数  
int main()
{
	linklist_t h = create_empty_linklist();   //创建空节点。 
	insert_linklist_1(h,11,1);           //按位置插入值。 
	insert_linklist_2(h,55);             //按大小插入值。 
	insert_linklist_2(h,33);
	insert_linklist_2(h,77);
	insert_linklist_2(h,77);
	insert_linklist_2(h,22);
	insert_linklist_2(h,88);

	visit_linklist(h);       //遍历。 
	
	delete_linklist_1(h,4);     //按位置删除。 
	delete_linklist_2(h,77);    //按数值删除大小。 

	int s = 0;
	get_linklist(h,4,&s);        //到指定位置寻找数值。 
	printf("s : %d\n",s);

	puts("which num you want to search :");     //输入一个要找的值。          
	scanf("%d",&s);
	int pos = search_linklist(h,s);
	if(pos == -1)  					//判断此数值是否存在。 
		printf("Not found\n");
	else 
		printf("In :%d\n",pos);

	visit_linklist(h);       //遍历。 
	clear_linklist(h);       //清空链表。 
	puts("And:");
	visit_linklist(h);      //遍历   
	return 0;
}

//链表应用1:
//两个有序表,形成一个新的有序表
//完成功能: 创建空链表、求表长、遍历链表、插入、清空、实现合并、测试函数。
A : 11 33 44 77 88
B : 22 55 66 99

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

typedef int data_t;
typedef struct node_t
{
	data_t data;
	struct node_t * next;
}linknode_t, *linklist_t;      

linklist_t create_empty_linklist()
{
	linklist_t h = (linklist_t )malloc(sizeof(linknode_t ));//sizeof(linknode_t);求结构体的大小,不求指针的大小 
	h->next = NULL;
	return h;
}

int empty_linklist(linklist_t h)
{
	return  (h->next == NULL) ;    
}

int length_linklist(linklist_t h)
{
	int len = 0;
	while(h->next != NULL)
	{
		len++;
		h = h->next;
	}
	return len;
}

void visit_linklist(linklist_t h)
{
	h = h->next;
	while(h != NULL)
	{
		printf("%d\n",h->data);
		h = h->next;
	}
	return ;
}

int insert_linklist(linklist_t h,data_t value,int pos)
{
	if(pos < 1 || pos > length_linklist(h)+1)
		return -1;

	while(--pos)
		h = h->next;

	linklist_t new = (linklist_t )malloc(sizeof(linknode_t ));
	new->data = value;
	new->next = h->next;

	h->next = new;
	return 0;
}

void clear_linklist(linklist_t h)
{
	if(empty_linklist(h) == 1)	
		return ;
	linklist_t f = NULL;

	while(h->next != NULL)
	{
		f = h->next;
		h->next = f->next;
		free(f);
	}
	return ;
}
void Merge(linklist_t p,linklist_t q)
{
	linklist_t h = p;
	p = p->next;
	q = q->next;

	while(q != NULL && p != NULL)   //确保要比较的两个节点,都有数据。 
	{
		if(p->data < q->data)     //比较大小,小的在前,大的在后。 
		{
			h->next = p;
			p = p->next;
		}
		else 
		{
			h->next = q;
			q = q->next;
		}
		h = h->next;
	}
	if(p != NULL)       //结束之后再做判断。 将没有结束的那个链表,连接到合并的链表中。形成一个完整的链表。 
		h->next = p;
	else 
		h->next = q;
	return ;
}

int main()
{
	linklist_t A = create_empty_linklist();
	linklist_t B = create_empty_linklist();
	
	insert_linklist(A,88,1);
	insert_linklist(A,77,1);
	insert_linklist(A,44,1);
	insert_linklist(A,33,1);
	insert_linklist(A,11,1);
	insert_linklist(A,99,6);
	insert_linklist(B,66,1);
	insert_linklist(B,55,1);
	insert_linklist(B,22,1);

	Merge(A,B);

	visit_linklist(A);

	clear_linklist(A);
	return 0;
}

三.单向循环链表实现

  将尾节点的指针域,赋值为头结点的地址。 形成一个闭环,就是单项循环链表。

//约瑟夫环代码

#include <stdio.h>
#include <stdlib.h>
typedef struct node_t 
{
	int data;
	struct node_t *next;
}linknode_t;

int main()
{
	linknode_t *h = (linknode_t *)malloc(sizeof(linknode_t ));   //创建第一个节点
	h->data = 1;     //数据域中存放编号为1. 不带头结点的链表。 
	h->next = NULL;

	linknode_t *new = NULL,*q = h,*t = NULL; //new 用来存放新创建的节点。q用来连接节点到链表中,t为要删除的节点。 
	int n = 8,k = 3,m = 4;   //8个人。从第3个人开始,数到4的出列。 

	int i;
	for(i=2; i<=n; i++)       //创建其余节点。 
	{
		new = (linknode_t *)malloc(sizeof(linknode_t ));  //创建 
		new->data = i;                 //赋值。 
		new->next = NULL;              
		q->next = new;                 //连接到链表当中。 
		q = new;                       //q 指向下一个节点。 
	}

	q->next = h;        //尾节点指针 指向 头节点。形成闭环。循环链表。 

	q = h;              //从头开始数数。 
	for(i=0;i<k-1;i++)    //找到起始位置。 
	{
		q = q->next;
	}

	while(q->next != q)    //如果此节点的指针域不指向自己,证明此时有多于一个的节点。 
	{
		for(i=1;i<m-1;i++)    //找出 数到4的节点的前一个位置。 
		{
			q = q->next;
			t = q->next;
		}
		
		printf("%5d",t->data);   //出列的节点的编号。   
		q->next = t->next;        //删除节点步骤1. 
		free(t);                  //步骤2. 
		q = q->next;              // q 向后移动一位。供下次数数。   
	}
	printf("\nThe end : %d\n",q->data);   //剩下的最后一个节点。 
	free(q);
	return 0;
}

四. 双向链表:

typedef struct node_t 
{
	char name[20];     //数据域。 
	struct node_t *prev;
	struct node_t *next;   //指针域。 
}linknode_t;

好处: 可以双向访问每个节点。
操作:
1)插入一个节点 : //当前新创建的节点称为q,插入位置的下一个节点称为p 。

a. q->prev = p->prev;    //前两步是给新节点赋值,后两步是将前后两个节点的指针,调整指向新节点。 
b. q->next = p;
c. p->prev->next = q;
d. p->prev = q;

2)删除一个节点 ://要删除的节点是 q

a. (q->prev)->next = q->next;
b. (q->next)->prev = q->prev;
c. free(q);

四.用链表实现多项式合并

A16(X)=5+2X+8X8+3X16, 相应的线性表:A((5,0),(2,1),(8,8),(3,16))
B8(X)=6X+23X6–8X8, 相应的线性表:B((6,1),(23,6),(-8,8))
A+B 的结果多项式C为:
C16(X)= 5 + 8X + 23X6 + 3X16 ,相应的线性表:C((5,0),(8,1),(23,6),(3,16))

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
	float coef;     //系数
	int exp;        //指数
} data_t;
typedef   struct node_t
{   
	data_t data;
    struct node_t *next;
}linknode_t, *linklist_t;

linklist_t create_empty_link()
{
	linklist_t h = (linklist_t )malloc(sizeof(linknode_t));
	h->next = NULL;
	return h;
}
void insert_linklist(linklist_t s,data_t value)
{
	while(s->next != NULL)
		s = s->next;
	linklist_t new = (linklist_t)malloc(sizeof(linknode_t));
	new->data = value;
	new->next = NULL;
	s->next = new;
	return ;
}
void clear_linklist(linklist_t s)
{
	linklist_t q = NULL;	
	while(s->next != NULL)
	{
		q = s->next;
		s->next = q->next ;
		free(q);
	}
	return ;
}
linklist_t  Merge_linklist(linklist_t s1,linklist_t s2)
{
	linklist_t C = create_empty_link();
	linklist_t new = C;

	s1 = s1->next;
	s2 = s2->next;

	while( s1 && s2 )
	{
		if( s1->data.exp < s2->data.exp )
		{	
			insert_linklist(new,s1->data);
			new = new->next;
			s1 = s1->next;
		}
		else if( s1->data.exp > s2->data.exp )
		{
			insert_linklist(new,s2->data);
			new = new->next;
			s2 = s2->next;	
		}
		else 
		{
			float sum = s1->data.coef + s2->data.coef;
			if( sum )
			{
				data_t v = {sum,s1->data.exp};
				insert_linklist(new,v);
				new = new->next;
				s1 = s1->next;
				s2 = s2->next;
			}
			else 
			{
				s1 = s1->next;
				s2 = s2->next;
			}
		}
	}
	if( s1 != NULL )
		new->next = s1;
	else 
		new->next = s2;
	return C;
}
int main()
{
	linklist_t A = create_empty_link();
	linklist_t B = create_empty_link();

	data_t ddd ;
	puts("Put A:coef  exp  :");
	while(1)
	{
		scanf("%f%d",&ddd.coef,&ddd.exp);
		if(ddd.coef == 0)
			break;
		insert_linklist(A,ddd);
	}

	puts("Put B:coef  exp  :");
	while(1)
	{
		scanf("%f%d",&ddd.coef,&ddd.exp);
		if(ddd.coef == 0)
			break;
		insert_linklist(B,ddd);
	}

	linklist_t result = Merge_linklist(A,B);

	while(result->next != NULL)
	{
		result = result->next;
		printf("%.2f   %d\n",result->data.coef,result->data.exp);
	}

	clear_linklist(A);
	clear_linklist(B);
	clear_linklist(result);
	return ;
}
//此代码的局限性: 创建第三个链表,没有考虑内存空间使用问题。还有 Merge_linklist 函数,调用其他函数,独立性差。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值