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

小猪的数据结构学习笔记(三)

时间:2014-07-29 15:16:38      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:数据结构   入门   快速   算法   笔记   

小猪的数据结构学习笔记(三)

线性表之单链表


本章引言:


上一节中我们见识了第一个数据结构——线性表中的顺序表;

当你把操作的代码自己写几遍就会有点感觉了,如果现在让你写顺序表的

插入算法,你能够想出大概的代码么?如果可以,那么你就可以进入新的章节了;

否则,还是回头看看吧!在本节,我们将迎来线性表的链式表示——单链表

单链表和顺序表有什么优势和劣势呢?单链表的头插法和尾插法有什么不同呢?

请大家跟随笔者的脚步来解析线性表中的单链表把bubuko.com,布布扣


本节学习路线图


bubuko.com,布布扣


路线图解析:

①先要理解顺序表和单链表各自的优点和缺点,考试常考的地方!

②熟记单链表的形式,理解头指针,头结点,尾结点,数据域与指针域!

③熟记单链表的结点结构代码

④区分头指针域头结点!

⑤两种方式创建单链表:头插法和尾插法

⑥单链表的12个基本操作

⑦有趣的算法::如何获得单链表中位置排中间的结点?



正文:


单链表的引入:

bubuko.com,布布扣



单链表的结构图:

bubuko.com,布布扣



单链表的结点存储结构

bubuko.com,布布扣



头指针与头结点的比较

bubuko.com,布布扣



头插法与尾插法创建表的比较:


①头插法的流程:

bubuko.com,布布扣

ps:最前面的代表头指针


代码:

<span style="font-family:Microsoft YaHei;">void HeadCreateList(LinkList &L,int n)
{
	LinkList p;
	int i;

	//初始化随机数种子,为头指针分配内存空间,并且指针域设置为空
	srand(time(0));
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	//利用循环,随机生成n个数字并且存储到单链表中:
	for(i = 0;i < n;i++)
	{
		//生成新的结点
		p = (LNode)malloc(sizeof(LNode));
		//生成两位数随机数就是100,三位就是1000,以此类推
		p -> data = rand()%100 + 1;
		p -> next = L - > next;
		L -> next = p;
	}
}	
</span>


代码步骤解析:

①初始化头结点,并且让头指针指向头结点,同时让头结点的指针域设置为NULL;

②构造单链表的结点,这里用的是随机生成,当然你也可以自己scanf!

③构造完后,让当前结点的指针域指向L指向的下一个结点

④将头指针指向当前结点




②尾插法的流程

bubuko.com,布布扣


PS:因为每次都是将新节点插入到链表尾部,所以需要加入一个指针R用于始终指向标的尾结点,以便

新节点插入到链表的尾部



代码

<span style="font-family:Microsoft YaHei;">void TailCraeteList(LinkList &L,int n)
{
	LinkList p,r;
	int i;

	srand(time(0));
	L = (LinkList)malloc(sizeof(LNode));
	L -> next = NULL;
	r = L;
	for(i = 0;i < n;i++)
	{
		L = (LNode)malloc(sizeof(LNode));
		p -> data = rand()%100 + 1;
		//这里要注意,p是中介结点,当前尾结点的next指向p
		r -> next = p;
		//r一直指向尾结点,此时p才是尾结点,所以吧p的值赋值给r
		r = p;
	}
	r -> next = NULL;
}</span>




代码步骤解析:

①构造一个头结点,让头指针指向头结点,同时把头指针的值赋值给指针R(R一直指向尾结点)

②随机生成n个随机数并且构造结点,同时将r的指针域指向p

③因为现在出现新的尾结点,中介变量p,所以r要再指向p,从而保证p一直指向为节点

④将为节点的指针域设置为NULL




有趣的算法:查找中间结点

如何获得单链表中位置排中间的结点?


分析:

访问单链表中的元素只能从头到尾一个个地挪动,貌似只有一个方法了,就是在记录单链表的长度了,

然后再除以2得出第几项为中间结点!假如我们不知道长度呢?有没有其他方法呢?答案肯定是有得,

这里提供一个简单的方法:用两个不同的指针,按照不同的移动顺序,暂且称为快慢指针,每次循环

①快指针每次挪动2个节点:p = p->next->next  ②慢指针每次挪动1个节点:q = q -> next;

当快指针到达尾部时,此时慢指针刚好指向中间结点!完成!


代码:

<span style="font-family:Microsoft YaHei;">Status GetMidLNode(LinkList L,ElemType &e)
{
	LinkList p,q;
	p = q = L;
	while(p -> next -> next != NULL)
	{
		if(p -> next -> next != NULL)
		{
			p = p -> next -> next;
			q = q -> next;
		}
		else 
		{
			p = p -> next;
		}
	}
	e = q -> data;
	return OK;
}	
</span>


代码就不解释了,慢慢理解下把!





十二个基本操作:


=====================================================================

====分割线,上面的是本节的重点和难点,基本操作都很简单,实在有兴趣的再往下看吧=====

=====================================================================


①单链表的存储结构:

<span style="font-family:Microsoft YaHei;">typedef struct LNode
{
	ElemType data;  //数据域
	struct Lnode *next; //指针域 
}LNode;
typedef struct LNode *LinkList;
//定义两个是方便使用 </span>




②构造空表

<span style="font-family:Microsoft YaHei;">void InitList(LinkList &L)
{
	L = (LinkList)malloc(sizeof(LNode));
	if(!L)exit(ERROR);
	L -> next = NULL;
} </span>


③将表置为空表:

<span style="font-family:Microsoft YaHei;">void ClearList(LinkList &L)
{
	LinkList p = L -> next;
	L -> next = NULL;
	//接着就是销毁除头结点外的结点了 
	while(p)
	{
		q = L -> next;
		//释放首元节点 
		free(L);
		//移动到当前的首元节点 
		L = q;
	}	
}</span>


④判断表是否为空表

有两种情况:

有头结点:   L -> next = NULL,此时表为空表

无头结点:   L = NULL ,此时L为头指针


<span style="font-family:Microsoft YaHei;">Status ListEmpty(LinkList L)
{
	//只需要判断头结点的指针域是否为空即可
	if(L -> next)return False;
	else return TRUE; 
}</span>



⑤销毁单链表

<span style="font-family:Microsoft YaHei;">void Destory(LinkList &L)
{
	LinkList q;
	while(L)
	{
		//除了头结点外的结点都删除
		//指向首元节点,不是头结点 
		q = L -> next;
		free(L);
		//删除后,重新指向首元 
		L = q;
	}
}</span>


⑥获得表的长度:

<span style="font-family:Microsoft YaHei;">int ListLength(LinkList L)
{
	int i = 0;
	LinkList p = L -> next;  //指向首元节点,非头结点
	while(p)
	{
		i++;
		p = p -> next;
	} 
	return i;
} </span>


⑦获得表中第i个元素的值

<span style="font-family:Microsoft YaHei;">Status GetElem(LinkList L,int i,ElemType &e)
{
	int j = 1;
	//指向首元,然后依次后移
	//如果到了结尾或者j的值大于i还没找到说明i不合法 
	LinkList p = L -> next;
	while(p&&j < i)
	{
		j++;
		p = p->next;
	}
	if(!p || j > i)return ERROR;
	e = p ->data;
	return OK;
}</span>


⑧查找表中是否有满足条件的元素

<span style="font-family:Microsoft YaHei;">int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
	int i = 0;
	LinkList p = L -> next;
	while(p)
	{
		i++;
		if(compare(p->data,e))return i;
		p = p -> next;
	}
	return 0;
} </span>


⑨返回某个结点的直接前驱

<span style="font-family:Microsoft YaHei;">Status BeforeElem(LinkList L,ElemType choose,ElemType &before)
{
	LinkList q,p = L -> next;
	while(p -> next)
	{
		q = p -> next;
		if(q ->data == choose)
		{
			before = p -> data;
			return OK;
		}
		//如果p的后继不为choose,向后移 
	}
	return ERROR;
}</span>


⑩返回某个结点的直接后继

<span style="font-family:Microsoft YaHei;">Status NextElem(LinkList L,ElemType choose,ElemType &behind)
{
	LinkList p = L -> next;
	while(p -> next)
	{
		if(p ->data == choose)
		{
			behind = p -> next -> data;
			return OK;
		}
		p = p -> next;
	}
	return ERROR;
} </span>


?往表中第i个位置插入元素

<span style="font-family:Microsoft YaHei;">Status ListInsert(ListList L,int i,ElemType)
{
	int j = 0;
	LinkList p,q = L;
	while(q && j < i - 1)
	{
		j++;
		q = q -> next;
	}
	if(!p && j > i - 1)return ERROR;
	p = (LinkList)malloc(sizeof(LNode));
	//要先让插入的结点的指针域指向插入位置的后继结点
	//再让插入节点的前驱的指针域指向插入结点
	//!!!顺序不能乱哦1 
	p -> data = e;
	p -> next = q -> next;
	q -> next = p;
	return OK;	
}</span>



?删除表中第i个位置的元素

<span style="font-family:Microsoft YaHei;">Status ListDelete(LinkList L,int i,ElemType &e)
{
	int j = 0;
	LinkList p,q = L;
	while(q -> next && j < i - 1)
	{
		j++;
		q = q -> next;	
	}
	//判断输入的位置是否合理
	if(!q -> next|| j > i - 1)
	return ERROR;
	//指向准备删除的结点 
	p = q -> next;
	//删除结点的前驱的指针域指向删除结点的后继 
	q -> next = p ->next;
	e = p -> data;
	//释放要删除的结点 
	free(p);
	return OK;
} </span>




?遍历单链表中的所有元素

<span style="font-family:Microsoft YaHei;">void ListTraverser(LinkList L,void(*visit)(ElemType))
{
	LinkList p = L -> next;
	while(p)
	{
		visit(p -> data);
		p = p -> next;
	}
	printf("\n");
}</span>



相关代码下载:

点击下载










小猪的数据结构学习笔记(三),布布扣,bubuko.com

小猪的数据结构学习笔记(三)

标签:数据结构   入门   快速   算法   笔记   

原文地址:http://blog.csdn.net/coder_pig/article/details/38229011

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