可复用的链式存储结构
</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;
}
//数据结构学习感觉有点难,不过坚持就是胜利,噢耶,加油
</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
#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;
}
//数据结构学习感觉有点难,不过坚持就是胜利,噢耶,加油