您的位置:首页 > 理论基础 > 数据结构算法

数据结构2学习笔记

2014-11-01 19:15 232 查看



可复用的链式存储结构




</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="http://img.blog.csdn.net/20130808235947734" style="border: none; max-width: 100%;" />                                 <img alt="" src="http://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="http://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;
}
//数据结构学习感觉有点难,不过坚持就是胜利,噢耶,加油

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: