码迷,mamicode.com
首页 > 其他好文 > 详细

C 链表  

时间:2016-06-06 23:56:49      阅读:350      评论:0      收藏:0      [点我收藏+]

标签:c 链表  


链表ADT操作的代码实现

struct list *create_list()//创建一个节点,返回值为list结构体指针
void traverse(struct list *ls)			//遍历链表
struct list *insert_list(struct list *ls,int n,int data)	//在指定位置插入元素,(首节点,在第几个节点插入,这个节点的data值)
int delete_list(struct list *ls,int n)		//删除链表元素,1链表首元素,要删除第几个?
int count_list(struct list *ls)		//返回链表元素个数,包括首节点
void  clear_list(struct list *ls)	//清空链表,保留首节点
int empty_list(struct list *ls)	//返回链表是否为空
struct list *local_list(struct list *ls,int n)		//返回链表对应的第N个节点的地址
struct list *elem_local(struct list *ls,int data)	//返回链表中数据域值data的节点地址
int elem_pos(struct list *ls,int data)		//返回链表中数据域值data的节点的序号
struct list *last_list(struct list *ls)		//返回链表的最后一个元素
void merge_list(struct list *ls1,struct list *ls2)	//把链表2的有效元素合并到链表1
void reverse_list(struct list *ls)                      //逆置链表









chunli@ubuntu:~/list$ cat main.c 
//单向链表
#include <stdio.h>
#include <stdlib.h>
 
struct list //链表结构体
{
	int data;		// 数据
	struct list *next;	//指针域,指向一下个域的指针
};

struct list *create_list()//创建一个节点,返回值为list结构体指针
{
	//方法1
	//struct list *p = (struct list *)malloc(sizeof(struct list));
	//p -> data = 0;
	//p -> next = NULL;
	//return p;

	// 方法2calloc 会自动清空内存
	return calloc(sizeof(struct list),1);
}

void traverse(struct list *ls)			//遍历链表
{
	// 方法1 
	//int i = 0;
	//struct list *p = ls;			//从给的这个节点开始遍历
	//printf("首节点的地址 %p,本节点的值 %d ,下一个节点的地址 %p\n",p,p->data,p->next);
	//p = p->next;

	//while(p)
	//{
	//	printf("节点%d的地址 %p,本节点的值 %d ,下一个节点的地址 %p\n",i,p,p->data,p->next);
	//	p = p->next;
	//	i++;
	//}

	//方法2【递归】
	if(ls)		//只要地址不为NULL
	{
		//先序递归
		printf("地址 %p,本节点的值 %d \n",ls,ls->data);
		traverse(ls->next);
		
	}
}

struct list *insert_list(struct list *ls,int n,int data)	//在指定位置插入元素,(首节点,在第几个节点插入,这个节点的data值)
{	
	struct list *p = ls;
	while(p && n--)
	{
		p = p->next;
	}
	if(!p) return NULL;//n指向了一个无效的位置
	else
	{
		struct list *node = create_list();
		node->data = data;
		//掐断原来的链表,重新组合
		node->next = p->next;
		p->next    = node;
		return node;
	}
}
int delete_list(struct list *ls,int n)		//删除链表元素,1链表首元素,要删除第几个?
{
	struct list *p = ls;
	while(p && n--)
	{
		p = p->next;
	}
	if(!p) return 0;//n指向了一个无效的位置
	else
	{
		struct list *node = p->next;	//记录待删除节点的地址
		if(!node) return 0;		//如果这个节点是无效的,就返回无效
		p->next = node->next;		//将该节点next指向待删除节点的next节点的next节点
		free(node);
		return 1;			//操作成功!
	}
	
}

int count_list(struct list *ls)		//返回链表元素个数,包括首节点
{
	struct list *p = ls->next;
	int count = 0;
	while(p)
	{
		count++;
		p = p->next;
	}
	return count;
}

void  clear_list(struct list *ls)	//清空链表,保留首节点
{
	struct list *p   = ls->next;	//要跳过首节点,进入该链表的第一个有效元素
	struct list *tmp;
	while(p)
	{	
		tmp = p->next;		//记录当前节点的next
		//p->next = NULL;	//没必要的操作	
		free(p);		//释放这个有效的元素
		p = tmp;
	}
	ls->next = NULL;		//链表清空后,首节点就是尾节点,一定设置为NULL
}

int empty_list(struct list *ls)	//返回链表是否为空
{
	if(ls->next)		//如果不为空,返回1
		return 1;	
	else			//如果  为空,返回0
		return 0;
}
struct list *local_list(struct list *ls,int n)		//返回链表对应的第N个节点的地址
{
	struct list *p = ls->next;			//立即指向首节点的下一个元素
	while(p && n--)
	{
		p = p->next;
	}
	return p;
}

struct list *elem_local(struct list *ls,int data)	//返回链表中数据域值data的节点地址
{
	struct list *p = ls->next;			//立即指向首节点的下一个元素
	while(p)
	{
		if(p ->data == data) {break;}
		p = p->next;
	}
	return p;
}
	
int elem_pos(struct list *ls,int data)		//返回链表中数据域值data的节点的序号
{
	struct list *p = ls->next;			//立即指向首节点的下一个元素
	int count = 0;
	while(p)
	{
		if(p ->data == data) {break;}
		p = p->next;
		count++;
	}
	return count;
}

struct list *last_list(struct list *ls)		//返回链表的最后一个元素
{
	struct list *p  =ls->next;
	struct list *back = p;			
	while(p)
	{
		back = p;
		p = p->next;
	}
	return back;
}
void merge_list(struct list *ls1,struct list *ls2)	//把链表2的有效元素合并到链表1
{
	struct list *last = last_list(ls1);
	last->next = ls2->next;
}
void reverse_list(struct list *ls)
{
	if(!(ls || ls->next || ls->next->next)) {return ;}	//只有大于1个有效节点,才需要逆置
	struct list *left   = NULL;				//记录上一个节点的地址,初始值的NULL刚好可以作为尾节点的next的NULL
	struct list *curr   = ls->next;				//记录当前节点的地址
	struct list *right  = NULL;				//遍历完原链表的所以元素
	while(curr)						//遍历完原链表的所有元素
	{
		right      = curr->next;			//下一个节点就是当前节点的next
		curr->next = left;				//第一次执行的时候,curr节点就是尾节点了,就将尾节点的next指向了NULL
		left       = curr;				//把当前的节点作为上一个节点
		curr       = right;				//把下一个节点作为当前节点
	}
	ls->next = left;					//原链表的最后的一个有效元素就已经变为left了,让链表节点指向这个left就好了。
}


int main()
{
	//链表操作,入门
	{
		struct list *first  = create_list();	//创建一个节点,为首节点
		struct list *second = create_list();	//再创建一个节点
		struct list *thrid  = create_list();	//再创建一个节点
		first  ->next = second;			//第一个指向第二个
		second ->next = thrid;			//第二个指向第三
		first  ->data = 1	;		//为节点设置数值
		second ->data = 2;
		thrid  ->data = 3;
		//traverse(first);
	
		//如果最后一个节点的指向不是NULL会怎样
		free(thrid);
		//second ->next = NULL;
		traverse(first);			//不可预期的结果
	
	
		//如何删除第二个节点?
		free(second);
		first  ->next = thrid;			//第一个指向第三个
	}


	/*	链表ADT操作的代码实现		*/
	printf("\n\n\n开始批量创建链表\n");
	struct list *node_start = create_list();	//此时链表的长度只有1个,有效元素个数为0
	for(int i=0;i<4;i++)				//在原来的首节点上插入10个,结果就是11个
	{
		//链表插入只能在首节点之后
		//insert_list(node_start,i,i+100);	//每次都在第i个位置插入,越后来插入的越靠后
		insert_list(node_start,0,i+100);	//每次都在第0个位置插入,越后来插入的越靠前
	}

	delete_list(node_start,0);			//在指定位置删除节点
	insert_list(node_start,2,666);			//在指定位置插入节点
	traverse(node_start);				//遍历链表
	printf("链表有效元素有%d个(不包括首节点)\n",count_list(node_start));	//返回这个链表元素的个数
	printf("第2个节点的数据是%d\n",local_list(node_start,2)->data);		//返回链表第N个有效元素的地址
	printf("最后一个元素的数据域是 %d\n",last_list(node_start)->data);	//返回链表 最后一个元素的地址

	printf("\n\n链表合并,结果输出\n");
	struct list *node2 = create_list();	
	for(int i=0;i<8;i++)				
	{
		insert_list(node2,0,i+33);	
	}
	merge_list(node_start,node2);			//把node2合并到node_start
	traverse(node_start);				//遍历链表

	printf("\n逆置链表,结果输出\n");
	reverse_list(node_start);
	traverse(node_start);				//遍历链表

	printf("\n\n\n清空链表\n");
	clear_list(node_start);				//清空链表
	traverse(node_start);				//遍历链表


	

	return 0;
}
chunli@ubuntu:~/list$






编译运行:


chunli@ubuntu:~/list$  gcc  -std=c99 main.c && ./a.out 
地址 0x1ce2010,本节点的值 1 
地址 0x1ce2030,本节点的值 2 
地址 0x1ce2050,本节点的值 0 



开始批量创建链表
地址 0x1ce2030,本节点的值 0 
地址 0x1ce2090,本节点的值 102 
地址 0x1ce2070,本节点的值 101 
地址 0x1ce20b0,本节点的值 666 
地址 0x1ce2050,本节点的值 100 
链表有效元素有4个(不包括首节点)
第2个节点的数据是666
最后一个元素的数据域是 100


链表合并,结果输出
地址 0x1ce2030,本节点的值 0 
地址 0x1ce2090,本节点的值 102 
地址 0x1ce2070,本节点的值 101 
地址 0x1ce20b0,本节点的值 666 
地址 0x1ce2050,本节点的值 100 
地址 0x1ce21d0,本节点的值 40 
地址 0x1ce21b0,本节点的值 39 
地址 0x1ce2190,本节点的值 38 
地址 0x1ce2170,本节点的值 37 
地址 0x1ce2150,本节点的值 36 
地址 0x1ce2130,本节点的值 35 
地址 0x1ce2110,本节点的值 34 
地址 0x1ce20f0,本节点的值 33 

逆置链表,结果输出
地址 0x1ce2030,本节点的值 0 
地址 0x1ce20f0,本节点的值 33 
地址 0x1ce2110,本节点的值 34 
地址 0x1ce2130,本节点的值 35 
地址 0x1ce2150,本节点的值 36 
地址 0x1ce2170,本节点的值 37 
地址 0x1ce2190,本节点的值 38 
地址 0x1ce21b0,本节点的值 39 
地址 0x1ce21d0,本节点的值 40 
地址 0x1ce2050,本节点的值 100 
地址 0x1ce20b0,本节点的值 666 
地址 0x1ce2070,本节点的值 101 
地址 0x1ce2090,本节点的值 102 



清空链表
地址 0x1ce2030,本节点的值 0 
chunli@ubuntu:~/list$


本文出自 “魂斗罗” 博客,请务必保留此出处http://990487026.blog.51cto.com/10133282/1786709

C 链表  

标签:c 链表  

原文地址:http://990487026.blog.51cto.com/10133282/1786709

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!