上篇一篇博客中我们介绍了线性表的顺序表示与实现:
顺序表是按照顺序将数据保存到内存之中,虽然存取方便但是也带来了一些问题:
1、顺序表必须申请一整块连续的内存;
2、插入删除元素时,当情况最坏时每个元素都要被移动;
这两个原因导致顺序表的效率较低,为解决这两个问题我们可以使用链式存储的链表来实现线性表:
1、链表是有一种采用动态存储的结构,可根据需要申请内存单元;----解决整块内存不够的情况;
2、当要插入删除某个元素时,只需调整前后结点指针即可;-----解决顺序表的整体移动问题;
过程分析(以单链表为例):
1、定义链表结构:
struct Node
{
int data;
Node *next;
}*head, *next;
2、单链表基本操作:
(1)初始化:
链表为空,返回链表的头结点指针;
Node *InitLink()
{
head = next = NULL;
return head;
}
(2)检测是否为空:
检测头指针是否为空,若为空证明链表为空,否则链表不为空,返回一个bool型的值;
bool IsEmpty()
{
return head;
}
(3)添加结点至尾部:
要传进去一个数据为结点中包含的数据;
如果链表为空,则令这个新节点为头结点;
否则,追加到当前结点的后面;
void push(int num)
{
if (!IsEmpty())
{
next->data = num;
head = next;
}
else
{
next->next = new Node;
next = next->next;
next->data = num;
}
next->next = NULL;
}
(4)添加结点至指定位置:
需要传进去两个参数,要添加的位置int index, 添加的结点数据int num;
先通过遍历找到相应位置(如果找到最后一个还没有到要添加的位置 就可以直接结束):
next = head;
for(int i(1); i < index; i++)
{
next = next->next;
if (!next)
return ;
}
找到之后令新结点的指针域指向标记为原本指向的下一个结点:temp->next = next->next;令标记位结点的指针域指向新结点即可:next->next = temp;这部分完整代码如下:void addIndex(int index, int num){Node *temp = new Node;next = head;for(int i(1); i < index; i++){
next = next->next;if (!next)return ;}
temp->data = num;temp->next = next->next;next->next = temp;}
(5)、删除指定结点(按照关键字,按照位置均可,此处以关键字为例):
要传入一个关键字,表示要删除链表关键字中与之相等的结点;
如果恰好要删除的是第一个头结点,那直接移动头结点指针到下一个元素,然后删除临时结点即可;
否则的话就要遍历查找,而且因为单链表不能操作上一个结点,所以我们在遍历寻找的时候要注意遍历循环的条件应该是当前的下一个是否和被删除关键字相等;
找到之后,定义一个临时的结点存放被找到的结点,然后令当前结点指向被删除结点的下一个结点元素,然后删除那个存有被删除结点的临时结点即可;
完整代码如下:
void del(int num)
{
Node *temp = new Node;
if (head->data == num)
{
temp = head;
head = head->next;
delete temp;
return;
}
else
{
next = head;
while (next->next)
{
if(next->next->data == num)
{
temp = next->next;
next->next = next->next->next;
delete temp;
return;
}
next = next->next;
}
}
}(6)、计算链表长度及输出链表:
这部分遍历就好很简单没有什么难的:
长度:
int length()
{
int code = 0;
Node *temp;
temp = head;
while (temp)
{
temp = temp->next;
++code;
}
return code;
}
输出:
void print()
{
Node *temp;
temp = head;
while (temp)
{
std::cout << temp->data << "\t";
temp = temp->next;
}
std::cout << std::endl;
}关于链表的基本操作我没有写查找,其实查找的话,我们在删除那部分已经有所体现出来,就是遍历时关键字的比对,就已经实现了查找的功能;
实际上链式表示与实现中,单恋表是最简单最简单的实现,除此之外,还有:
1、循环单链式:最后一个结点指针域指向头结点即可实现,实现长度,输出等基本操作时将遍历条件改为当next->next == head 时即可;
2、双链式:有两个指针域,分别指向上一个和下一个结点,双链式有可实现操作上一个结点的优势,更为灵活实用。
等其他比较好玩的链式结构,但基本的思想还是跟单链式的思想相似。
上面的实现是通过结构体实现链表,其实C++的话类也可以
完整代码如下(不包括测试部分函数):
class link
{
private:
struct Node
{
int data;
Node *next;
}*head, *next;
public:
link();
void push(int num);
void del(int num);
void print();
void addIndex(int index, int num);
int length();
};
link::link()
{
head = NULL;
}
void link::push(int num)
{
if (head == NULL)
{
next->data = num;
head = next;
}
else
{
next->next = new Node;
next = next->next;
next->data = num;
}
next->next = NULL;
}
void link::del(int num)
{
Node *temp = new Node;
if (head->data == num)
{
temp = head;
head = head->next;
delete temp;
return;
}
else
{
next = head;
while (next->next)
{
if(next->next->data == num)
{
temp = next->next;
next->next = next->next->next;
delete temp;
return;
}
next = next->next;
}
}
}
int link::length()
{
int code = 0;
Node *temp;
temp = head;
while (temp)
{
temp = temp->next;
++code;
}
return code;
}
void link::print()
{
Node *temp;
temp = head;
while (temp)
{
std::cout << temp->data << "\t";
temp = temp->next;
}
std::cout << std::endl;
}
void link::addIndex(int index, int num)
{
Node *temp = new Node;
next = head;
for(int i(1); i < index; i++)
{
next = next->next;
if (!next)
return ;
}
temp->data = num;
temp->next = next->next;
next->next = temp;
}