赞
踩
链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不必须相邻,那么 怎么表示逻辑上的相邻关系呢?可以给每个元素附加一个指针域,指向下一个元素的存储位 置。如图所示:
从图中可以看出,每个结点包含两个域:数据域和指针域,指针域存储下一个结点的地址, 因此指针指向的类型也是结点类型
链表的核心要素:
其结构体的定义:
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}LinkList,LinkNode;
链表的节点均单向指向下一个节点,形成一条单向访问的数据链
他可以想象成一条链,每一节都挨在一起.如下图所示
需要注意的是链表头结点都不会有数据,它只有指针域,指向下一个元素的存储位.
而最后一个节点会有数据,但是他的指针域会指向NULL
的位置!
代码例子如下:
typedef struct _LinkNode
{
int data;
struct _LinkNode* next;
}LinkNode, LinkList;
bool InitList(LinkList*& L)
{
L = new LinkNode;
if (!L) return false;
L->next = NULL;
return true;
}
正如之前所说的, 头结点不会有数据存储,只会有指针域,指向下一个元素的存储位
问题:为什么 LinkList*& L
需要使用引用?
答: 这是因为如果没有引用的话,原本在main
函数里传递的这个指针将传的是一个形参. 这将导致main
函数里的 LinkList*
指针不会正真的指向 InitList
函数里的 new LinkNode
. 当InitList
函数结束时 main
函数里的 LinkList*
还是会指向NULL
代码例子如下:
bool ListInsert_front(LinkList*& L, LinkNode* node)
{
if (!L || !node) return false;
node->next = L->next;
L->next = node;
return true;
}
这里需要深入了解的地方是:
代码例子如下:
bool ListInsert_end(LinkList*& L, LinkNode* node)
{
if (!L || !node) return false;
LinkNode* last = NULL;
last = L;
while (last->next)
{
last = last->next;
}
node->next = NULL;
last->next = node;
}
这里需要注意的地方是:
代码里的while
循环是为了寻找到链表的最后一个节点, 所以里面的判断为last->next
. 当这个为false
时,last
将会指向最后一个节点.
因此,把node当成最后一个节点修改它的指针域为 NULL
,并且把原本应该是最后一个节点的指针域指向新的node
位置.
bool LinkInsert(LinkList*& L, int i, int& e) { if (!L) return false; int j = 0; LinkList* p, *s; p = L; while (p && j < i - 1) //Search for the position i-1 node, p will pointing to the node { p = p->next; j++; } if (!p || j > i - 1) { return false; } s = new LinkNode; //Construct new node s->data = e; s->next = p->next; p->next = s; return true; }
这里需要注意的地方是:
while (p && j < i - 1)
这个循环之所以要-1是因为我们先要指向要插入节点的位置的前一个节点. 以便可以让当前的这个节点的指针域指向新的节点s
代码里需要if (!p || j > i - 1)
的原因是用户可能输入要插入的值为负数,这样的话是不可能能在链表里插入的,所以我们要做防御式编程. 而 !p
的 目的也是一样可能链表只有5个节点 但是用户输入要在第10个节点插入!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。