数据结构2学习笔记



                            可复用的链式存储结构




</pre>本节知识点:</h1><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">1.链表的好处:对于动态链表,可以对未知数据量的数据进行存储。插入和删除比顺序表方便的多,不用大量移动。</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   链表的缺点:除了数据信息,还需对额外的链表信息进行分配内存,占用了额外的空间。访问指定数据的元素需要顺序访问之前的元素。</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">2.链表的基本概念:</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   链表头(表头节点):链表中的第一个节点,包含指向第一个数据元素的指针以及链表自身的一些信息(即链表长度length)</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   数据节点:链表中的代表数据元素的节点,包含指向下一个数据元素的指针和数据元素的信息</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   尾节点:链表中的最后一个数据节点,其下一元素指针为空,表示无后继</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">3.<span style="color: rgb(255, 0, 0);"><strong>对于本节的可复用单链表的设计想法是这样的:</strong></span></div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   a. 可复用的顺序表中保存的是各个数据的地址,所以我最初想到的是在链表元素中也保存各个数据的地址:</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">   <img alt="" src="https://img-blog.csdn.net/20130808235947734" style="border: none; max-width: 100%;" />                                 <img alt="" src="https://img-blog.csdn.net/20130809000824578" style="border: none; max-width: 100%;" /></div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">     使用这样的结构,add是链表中保存的数据,其实就是想复用保存的各种类型的地址,add是一个unsigned int型,用来保存各种数据类型的地址,next是链表结构,用来指向链表元素的下一个链表元素的。</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">     b.但是这样的结构有一个问题,就是从使用的总空间(链表结构的空间+add中保存数据的空间)角度来看,add就是一个浪费空间的变量。因为在add中保存地址,为什么不强制类型成next的类型(此时next应该是链表第一个结构的类型),直接使用这个地址把各种你想要存储的结构赋值给next,这样存储的各个结构就变成了,如图。</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">     <img alt="" src="https://img-blog.csdn.net/20130809002337734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWJoXzE5OTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="border: none; max-width: 100%;" /></div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">    c.但是把所有的类型都转换成链表第一个元素的指针类型 再赋值给next 显得程序很不规整,所以最好直接给链表一个结构,把这些结构类型都统一强制类型转换成这个链表的类型,如下:</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">    <div class="dp-highlighter bg_cpp" style="font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; width: 959.296875px; overflow: auto; padding-top: 1px; margin: 18px 0px !important;"><div class="bar" style="padding-left: 45px;"><div class="tools" style="padding: 3px 8px 10px 10px; font-size: 9px; line-height: normal; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; color: silver; background-color: rgb(248, 248, 248); border-left-width: 3px; border-left-style: solid; border-left-color: rgb(108, 226, 108);"><strong>[cpp]</strong> <a target=_blank target="_blank" href="http://blog.csdn.net/mbh_1991/article/details/9842823#" class="ViewSource" title="view plain" style="color: rgb(160, 160, 160); text-decoration: none; background-image: none; background-color: inherit; border: none; padding: 1px; margin: 0px 10px 0px 0px; font-size: 9px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: initial initial; background-repeat: initial initial;">view plain</a><a target=_blank target="_blank" href="http://blog.csdn.net/mbh_1991/article/details/9842823#" class="CopyToClipboard" title="copy" style="color: rgb(160, 160, 160); text-decoration: none; background-image: none; background-color: inherit; border: none; padding: 1px; margin: 0px 10px 0px 0px; font-size: 9px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-position: initial initial; background-repeat: initial initial;">copy</a><div style="position: absolute; left: 377px; top: 1547px; width: 18px; height: 18px; z-index: 99;"></div><div style="position: absolute; left: 941px; top: 14058px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1" class="dp-cpp" style="padding: 0px; border: none; list-style-position: initial; list-style-image: initial; background-color: rgb(255, 255, 255); color: rgb(92, 92, 92); margin: 0px 0px 1px 45px !important;"><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;"><span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit; font-weight: bold;">typedef</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> </span><span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit; font-weight: bold;">struct</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> Str_LinkList LinkListNode;  </span><span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//这个结构体是链表的真身 </span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li style="margin: 0px !important; padding: 0px 3px 0px 10px !important; border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; background-color: rgb(248, 248, 248); color: rgb(85, 85, 85); line-height: 18px;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;"><span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); background-color: inherit; font-weight: bold;">struct</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> Str_LinkList   </span><span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//每一个链表元素的结构都会包含这个结构  因为当给链表元素强制类型 </span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">{                     <span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//转换成(LinkListNode* )的时候  其实就是要开始对每个元素中的 LinkListNode进行赋值了 </span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li style="margin: 0px !important; padding: 0px 3px 0px 10px !important; border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; background-color: rgb(248, 248, 248); color: rgb(85, 85, 85); line-height: 18px;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    LinkListNode* next;  </span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">};  </span></li></ol></div>     把什么链表头啊,链表元素啊,想要连接进入这个链表的各种结构都强制类型成 LinkListNode*   但是要保证每个结构中都有LinkListNode* next 成员。</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">     d.最后一点,就有点接受不了,也是为了代码的整洁,提高可读性,使链表结构都规整到LinkListNode这个结构中去,便于对链表进行管理,比如说双向链表的前驱和后继。把每个类型中的LinkListNode* next 成员  变成LinkListNode node。<strong><span style="color: rgb(255, 0, 0);">这里面有一个很好的c语言技巧,就是这个LinkListNode node必须要放在每个结构中(如 str)的第一个元素位置,即node的地址就是结构体str的地址,因为只有这样了,在把str强制类型转换成 n=(LinkListNode* )str的时候,访问n->next才是访问str.node->next的值,因为两者地址相同,切记一定要放到第一个元素的位置!!!</span></strong></div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;">4.对于链表这个数据结构,一定要注意一个问题,也是这节我犯的一个很难发现的错误:</div><div style="color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial; font-size: 14px;"><strong><span style="color: rgb(255, 0, 0);">   就是已经在链表中的元素,千万不要再一次往链表中进行插入,因为这样会导致从它插入的地方开始链表的后继就开始混乱了,把整个链表完全弄乱,出现你想不到的问题。</span></strong></div><h1 style="margin: 0px; padding: 0px; color: rgb(54, 46, 43); line-height: 26px; background-color: rgb(231, 229, 220); font-family: Arial;"><a target=_blank name="t3" style="color: rgb(106, 57, 6); background-image: none; border: none; padding: 0px; margin: 0px;"></a><a target=_blank target="_blank" name="t1" style="color: rgb(255, 153, 0); background-image: none; border: none; padding: 0px; margin: 0px;"></a>本节代码:</h1><div>//头文件1.h</div><div><pre name="code" class="cpp">#ifndef _LINKLIST_H_
#define _LINKLIST_H_//防止头文件重复定义

typedef void LinkList;
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
	LinkListNode* next;
};

LinkList* LinkList_Create();

void LinkList_Destroy(LinkList* list);//销毁链表

void LinkList_Clear(LinkList* list);//链表清空

int LinkList_Length(LinkList* list);//获得其长度

int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);//插入元素地址

LinkListNode* LinkList_Get(LinkList* list, int pos);//得到元素地址

LinkListNode* LinkList_Delete(LinkList* list, int pos);//删除元素

#endif
//1.c函数
#include <stdio.h>
#include <malloc.h>
#include "LinkList.h"

typedef struct _tag_LinkList
{
	LinkListNode header;//指针域
	int length;
} TLinkList;//头结点

LinkList* LinkList_Create() // O(1)
{      //创建头结点
	TLinkList* ret = (TLinkList*)malloc(sizeof(TLinkList));//分配一个TlinkList的内存空间,使ret指向头结点

	if (ret != NULL)
	{
		ret->length = 0;//开始将长度至为0
		ret->header.next = NULL;//头结点指向为空
	}

	return ret;//返回头结点地址
}

void LinkList_Destroy(LinkList* list) // O(1)
{
	free(list);//删除头结点,感觉这样不是销毁
}

void LinkList_Clear(LinkList* list) // O(1)
{
	TLinkList* sList = (TLinkList*)list;  //void类型转换为结构体类型

	if (sList != NULL)
	{
		sList->length = 0;//将长度值为零
		sList->header.next = NULL;//头地址为0;
	}
}
                         //头结点地址
int LinkList_Length(LinkList* list) // O(1)//获取长度
{
	TLinkList* sList = (TLinkList*)list;//头结点
	int ret = -1;

	if (sList != NULL)
	{
		ret = sList->length;
	}

	return ret;//返回其长度
}
                     //   //这个就是内部为结构体指针的结构体的地址   
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos) // O(n)
{
	TLinkList* sList = (TLinkList*)list;//得到头结点结构体地址 
	int ret = (sList != NULL) && (pos >= 0) && (node != NULL);//判断其合法性
	int i = 0;

	if (ret)
	{       //<span style="color:#ff0000;">/这里相当精妙  TLinkList指针指向的区域转换为(LinkListNode*)//刚刚好是指针域的地址,这是精妙之处,得到指针域的地址</span>
		LinkListNode* current = (LinkListNode*)sList;//相当于一个结构体指针域

		for (i = 0; (i < pos) && (current->next != NULL); i++)
		{
			current = current->next;//指向n个地方
		}

		node->next = current->next;//插入到链表中第一项
		current->next = node;

		sList->length++;//然后长度++//插入然后++
	}

	return ret;//返回1就是成功;
}
                          //结构体地址,   传入
LinkListNode* LinkList_Get(LinkList* list, int pos) // O(n)  //第3个位置
{             //头结点指针
	TLinkList* sList = (TLinkList*)list;//指向头结点
	LinkListNode* ret = NULL;
	int i = 0;

	if ((sList != NULL) && (0 <= pos) && (pos < sList->length))
	{     //指向指针域地址
		LinkListNode* current = (LinkListNode*)sList;//指向指针域

		for (i = 0; i < pos; i++)
		{
			current = current->next;
		}

		ret = current->next;//得到插入元素 (结构体) 地址
	}

	return ret;
}
                            //传入头结点地址   //下标
LinkListNode* LinkList_Delete(LinkList* list, int pos) // O(n)
{
	TLinkList* sList = (TLinkList*)list;
	LinkListNode* ret = NULL;
	int i = 0;

	if ((sList != NULL) && (0 <= pos) && (pos < sList->length))//判断合法性
	{
		LinkListNode* current = (LinkListNode*)sList;//指针域

		for (i = 0; i < pos; i++)
		{
			current = current->next;
		}

		ret = current->next;
		current->next = ret->next;

		sList->length--;
	}
	return ret;
}
//主函数
#include <stdio.h>
#include <stdlib.h>
#include "LinkList.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

struct Value   //相当于元素
{
	LinkListNode header;//头结点
	int v;
};

int main(int argc, char *argv[])
{
	int i = 0;
	LinkList* list = LinkList_Create();//得到其地址,用list指针指向创建的结构体

	struct Value v1;//定义结构体变量
	struct Value v2;
	struct Value v3;
	struct Value v4;
	struct Value v5;

	v1.v = 1;
	v2.v = 2;
	v3.v = 3;
	v4.v = 4;
	v5.v = 5;
	                       //传入刚刚的那个结构体的地址强制转换为
	                      //传入指针并强制转换为(LinkListNode*)
	LinkList_Insert(list, (LinkListNode*)&v1, LinkList_Length(list));
	LinkList_Insert(list, (LinkListNode*)&v2, LinkList_Length(list));
	LinkList_Insert(list, (LinkListNode*)&v3, LinkList_Length(list));
	LinkList_Insert(list, (LinkListNode*)&v4, LinkList_Length(list));
	LinkList_Insert(list, (LinkListNode*)&v5, LinkList_Length(list));

	for (i = 0; i<LinkList_Length(list); i++)
	{
		struct Value* pv = (struct Value*)LinkList_Get(list, i);
		
		printf("%d\n", pv->v);
	}

	while (LinkList_Length(list) > 0)
	{
		
		struct Value* pv = (struct Value*)LinkList_Delete(list, 0);
		
		printf("%d\n", pv->v);
	}

	LinkList_Destroy(list);
	system("pause");
	return 0;
}
//数据结构学习感觉有点难,不过坚持就是胜利,噢耶,加油






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值