链表是指线性表的链式存储结构,,与数组有区别,数组是连续存储,而链表存储单元可以是连续的也可是不连续的。为了存储数据元素的信息以及存储数据元素之间的关系的信息,我们称之为结点(node)。其中node包括数据域和指针域,在线性表中最多会用一个直接前驱元素和直接后继元素。
咱们最常用的就是设置一个直接后继元素构成单链表,但也有设置一个前驱一个后继,我们称之为双向链表,在创建链表我们也会设置头指针和尾指针,头指针指向第一个元素所在的结点的位置,而尾指针指向末端元素所在的结点的位置。
首先咱们介绍一下单链表,单链表上面也提到了一些,其结点包括数据域和指针域,数据域存放信息,而指针域存放后继元素(为了将当前结点与下一个结点链接,这里后继指针指向的为下一个结点的位置),咱们这里可以通过结构体的知识来定义结点:
struct Node
{
int data;//数据域
struct Node* next;//指针域
};
这里为了表示方便咱们可以直接利用typedef简化写法:
typedef struct Node
{
int data;//数据域
struct Node* next;//指针域
}node,*linklist;
这里咱们node为结构体元素,linklist为结构体指针。
接下来如何创建链表呢?
首先创建无参头结点:
void create_headnode()
{
linklist head = (linklist)malloc(sizeof(node));
head->next = NULL;//指针指向为空,防止野指针
}
这个时候咱们也可以写一个判断链表是否为空的函数:
void emply_node(linklist head)
{
if(head->next == NULL) return true;
else return false;
}
有了头结点,接下来咱们就要插入结点了:
头插法也可以说其是一个链表反向的操作,将结点每次插在头结点: head->.....->a4->a3->a2->a1
头插法的精髓其实就是如何进行链接?方法就是将头结点的指针域指向插入结点的地址,插入的结点的指针域指向头结点的指针域在新结点插入之前所指向的地址。
p->next = head->next;
head->next = p;
了解完链接过程接下来不断创建结点继续插入就OK了:
void head_create(linklist head,int n)
{
head->next = NULL;//头结点指针域初始化
for(int i = 1;i <= n;i++)
{
linklist p = (linklist)malloc(sizeof(node));
cin >> a;
p->data = a;
p->next = head->next;
head->next = p;
}
}
2. 尾插法
尾插法就是每次插入到末尾结点的后面,按照上面的分析如何链接呢?
首先尾指针tail要保证始终指向尾结点,插入结点的指针域指向尾结点的指针域,插入结点的地址为尾结点的指针域指向的地址,然后tail指向新的尾结点:head->a1->a2->a3->.....
p->next = tail->next;
tail->next = p;
tail = p;
代码如下:
void tail_next(linklist head,int n)
{
head->next = NULL;
linklist tail = head;
for(int i = 1;i <= n;i++)
{
linklist p = (linklist)malloc(sizeof(node));
cin >> p->data;
p->next = tail->next;
tail->next = p;
tail = p;
}
}
咱们在了解了如何插入结点后,接下来就了解一下如何单插入两结点之间:
假设想将结点p插入到结点s与结点t之间,那么链接线,p的指针域指向s的指针域,s的指针域指向p的地址,然后就是这样:
p->next = s->next;
s->next = p;
随后就是查找s,咱们要从头结点开始查找(时刻想着设置无参头结点,方便查找),查找也就是不断刷新指针q的指向:q = q->next
void insert(linklist head,int n)
{
int count = 0;//计数
linklist q = head;
while(q != NULL && count < n)
{
count++;
q = q->next;
}
if(q == NULL) throw"插入异常";
else
{
linklist p = (linklist)malloc(sizeof(node));
cin >> p->data;
p->next = q->next;
q->next = p;
}
}
最后咱们想删除链表释放空间如何操作呢?
这里利用delete释放空间,引出一下析构函数,析构函数用于注意删除单链表中的各个结点,释放存储空间,这里注意要设置工作指针保存被删除的结点的指针域,以此来防止丢失后面结点的地址。
void ~head_create(linklist head)
{
linklist p = head;
whill(p != NULL)
{
linklist q = p;
p = p->next;//工作指针
delete q;
}
}
以上就是关于单链表的相关知识,各位看完也可以尝试打出按位查找的代码,这里因为包含了就不具体说明,记住一点就可以:注意指针的指向就OK了。
好了今天就到这里了,后序会给大家带来有关双向链表的相关知识,感谢收看,别忘记三连支持啊。