带头结点的单链表简单操作:
# include <malloc.h>
# include <stdio.h>
# include <iostream>
using namespace std;
typedef struct node
{
int data;
struct node* next;
}Lnode,*Linklist;
int Listinsert(Linklist &L, int i, int e)
{
//在带头节点单链表L中第i个位置之前插入元素e
Linklist p = L; //链表头结点
Linklist s; //新建节点指针
int j = 0; //计数器
//插入节点:一般使用while(p),主要是考虑到从链表的表尾也可以插入节点
while (p && j < i-1) //找到第i-1个节点,p指向第i-1个节点
{
p = p->next;
++j;
}
if (!p || j > i-1) //非法删除
return 0;
s = (Linklist)malloc(sizeof(Lnode)); //生成新节点
s->data = e;
s->next = p->next; //新节点连接后面的节点(原来的第i节点)
p->next = s; //新节点连接前面的节点(原来的第i-1节点)
return 1;
}
int Listdelete(Linklist& L, int i)
{
//在带头节点单链表L中删除第i个位置元素,由e返回
Linklist p = L; //链表头结点
Linklist s; //指向要删除的节点
int j = 0; //计数器
//删除节点:建议使用while(p->next),可以防止删除尾节点时指针指空,删除操作失败。
while (p->next && j < i - 1) //找到第i-1个节点,p指向第i-1个节点
{
p = p->next;
++j;
}
if (!(p->next) || j > i - 1)
return 0;
s = p->next; //保存第i节点的指针
p->next = s->next; //第i-1个节点的指针指向第i+1个节点
int e;
e = s->data ; //保存数据
free(s); //释放空间
return 1;
}
void Createlist(Linklist& L, int n)
{
//逆位序输入n个元素的值,建立带头节点的单链表
Linklist p;
L = (Linklist)malloc(sizeof(Lnode));
L->data = 9999;
L->next = NULL; //先建立一个带头节点的单链表
for (int i = n; i > 0; --i)
{
p = (Linklist)malloc(sizeof(Lnode)); //生成新节点
scanf_s("%d",&p->data);
p->next = L->next;
L->next = p;
}
}
void Mergelist(Linklist& La, Linklist& Lb)
{
//已知单链表La和Lb的元素按值非递减排列,归并La和Lb得到新链表Lc,Lc也是安值非递减排列
Linklist pa, pb, pc;
pa = La->next;
pb = Lb->next;
pc = La; //用La的头结点作为Lc的头结点
while (pa && pb)
{
if (pa->data <= pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa ? pa : pb;
free(Lb);
}
int main()
{
Linklist list_one,list_two;
Createlist(list_one, 5);
Createlist(list_two, 5);
cout << "从链表头节点开始输出第一个链表";
Linklist pa = list_one;
while (pa)
{
cout << pa->data << ' ';
pa = pa->next;
}
cout << endl << "从链表第一个节点开始输出第一个链表";
Linklist pa_a = list_one->next;
while (pa_a)
{
cout << pa_a->data << ' ';
pa_a = pa_a->next;
}
cout << endl << "从链表第一个节点开始输出第二个链表";
Linklist pb = list_two->next;
while (pb)
{
cout << pb->data << ' ';
pb = pb->next;
}
cout << endl << "从链表第一个节点前插入100";
Listinsert(list_one, 1, 100);
cout << endl << "从链表第一个节点开始输出第一个链表";
Linklist pa_b = list_one->next;
while (pa_b)
{
cout << pa_b->data << ' ';
pa_b = pa_b->next;
}
cout << endl << "从链表删除第一个节点";
Listdelete(list_one, 1);
cout << endl << "从链表第一个节点开始输出第一个链表";
Linklist pa_c = list_one->next;
while (pa_c)
{
cout << pa_c->data << ' ';
pa_c = pa_c->next;
}
cout << endl << "合并两个链表";
Mergelist(list_one, list_two);
cout << endl << "从链表第一个节点开始输出第一个链表";
Linklist pa_d = list_one->next;
while (pa_d)
{
cout << pa_d->data << ' ';
pa_d = pa_d->next;
}
}
运行结果
带头结点和不带头结点的线性链表的区别
1.所有的链表都要有个头指针first,带头结点的链表的头指针指向的是头结点,头结点的指针域指向首元结点,不带头结点的头指针直接指向首元结点。
2.两者在操作上有区别:在删除和插入操作中,无论删除和插入的位置如何,带头结点的链表不需要修改头指针的值,而不带头结点的有时候需要。在清空操作中,带头结点的保留头结点,而不带头结点的要销毁。
3.在结构上,带头结点的单链表,不管链表是否为空,均含有一个头结点,不带头结点的单链表不含头结点。
4.在操作上,带头结点的单链表的初始化为申请一个头结点。无论插入或删除的位置是地第一个结点还是其他结点,算法步骤都相同。不带头结点的单链表,其算法步骤要分别考虑插入或删除的位置是第一个结点还是其他结点。
带头节点的单链表、双链表插入与删除,指针指向第i-1个节点,单链表插入操作:先从新节点出发向后连接,在向前连接,删除操作从第i-1结点向第i+1节点连接,双链表插入操作:先从新节点出发向后连接,回到新节点在向前连接,再回到新节点,删除操作从第i-1结点向第i+1节点连接,再从第i+1节点回到第i-1节点。