1、静态链表
class Link
{
public:
int age;
char name[20];
Link *next;
};
int main()
{
//声明3个节点对象,表明链表中有3个元素
Link lnk[3];
//声明头指针节点和一个临时的指针节点
Link *head, *p;
//对节点赋值
lnk[0].age = 21;
strcpy_s(lnk[0].name, "张三");
lnk[1].age = 23;
strcpy_s(lnk[1].name, "李四");
lnk[2].age = 25;
strcpy_s(lnk[2].name, "王五");
//设置头节点(头节点通常指向链表的第一个元素)
head = &lnk[0];
//对节点中的next指针赋值,将其串联成链表
lnk[0].next = &lnk[1];
lnk[1].next = &lnk[2];
//最后一个节点中没有其他节点指针了,所以为NULL
lnk[2].next = NULL;
//把头节点赋给临时节点
p = head;
//遍历链表
while(p)
{
cout<<p->age<<" "<<p->name<<endl;
//每次循环,p都会发生变化,这就是要把head赋给p的原因
//要是直接用head遍历,那后面再要用到头节点head的时候,就找不到链表首地址了
p = p->next;
}
return 0;
}
2、动态链表
(1)动态创建
class Link
{
public:
int age;
char name[20];
Link *next;
};
//头节点
Link *Head = NULL;
Link *Create()
{
//p1作为新节点指针,p2作为旧节点指针
Link *p1, *p2;
//先动态开辟一个新节点
p1 = new Link;
//设置链表的初始状态
Head = p2 = p1;
cout<<"输入年龄(0退出):";
cin>>p1->age;
if (p1->age != 0)
{
cout<<"输入姓名";
cin>>p1->name;
}
else
{
delete p1;
Head = p2 = p1 = NULL;
return Head;
}
while (p1->age != 0)
{
//每次循环,p1都会创建一个新的节点,在创建新节点之前,要把旧节点保存到p2
p2 = p1;
p1 = new Link;
cout<<"输入年龄(0退出):";
cin>>p1->age;
if (p1->age != 0)
{
cout<<"输入姓名";
cin>>p1->name;
}
//把新创建的节点保存到p2的指针域,这样做是因为p2负责保存旧节点,p1负责创建新节点,p2->next保存新创建的节点,环环相扣
//因为一开始p,p1,Head都是指向相同的地址,而且Head的地址一直不会改变,所以利用Head头指针就可以遍历整个链表
p2->next = p1;
}
//释放p1
delete p1;
//把p2的指针域置空,但是p2本身是有数据的,是尾节点
p2->next = NULL;
return Head;
}
void Show(Link *head)
{
while (head)
{
cout<<head->age<<" "<<head->name<<endl;
head = head->next;
}
}
(3)链表长度
int Length(Link *p)
{
int n = 0;
while(p)
{
n++;
p = p->next;
}
return n;
}
(4)删除链表
void Delete(Link *lst, char *name)
{
Link *next;
Link *pre;
//第一个节点即为要删除的目标
if (strcmp(lst->name,name) == 0)
{
//保存第一个节点的指针域,把下一个节点作为头节点
next = lst->next;
//删除目标节点
delete lst;
//更新一下全局的头指针
::Head = next;
return;
}
while (lst)
{
if (strcmp(lst->name,name) == 0)
{
//目标是最后一个链表元素
if (lst->next == NULL)
{
//pre->next是当前的节点lst,因为是最后一个节点,所以指针域赋空
pre->next = NULL;
//让lst指向前一个节点
lst = pre;
//删除节点,这个节点就是之前的lst
delete pre->next;
return;
}
else
{
//把当前节点lst的下一个节点赋值给它的上一个节点的下一个节点,意思就是断开当前节点lst与链表的关系
pre->next = lst->next;
//记录当前节点地址,以便后面删除
next = lst;
//让lst指向前一个节点
lst = pre;
//释放原先lst所占的内存
delete next;
return;
}
}
//记录链表循环的上一次指向地址
pre = lst;
lst = lst->next;
}
}
(5)插入节点
void Insert(Link *lst, Link *insertData, int pos)
{
assert(lst);
assert(insertData);
Link *pre;
//如果指定位置是0或1或小于0,默认插入到第一个位置
if (pos >= 0 && pos <= 1)
{
insertData->next = lst;
::Head = insertData;
return;
}
//在链表的中间和末尾插入
int n = Length(lst);
int npos = 1;
while (lst)
{
//末尾插入
if (pos > n)
{
while (lst)
{
if (lst->next == NULL)
{
insertData->next = NULL;
lst->next = insertData;
return;
}
lst = lst->next;
}
return;
}
//中间插入
if (npos == pos)
{
//把lst添加新节点的next域
insertData->next = lst;
//现在lst是原来它前面的一个节点
lst = pre;
//新节点添加到链表
lst->next = insertData;
return;
}
pre = lst;
lst = lst->next;
npos++;
}
}
(6)测试链表
int main()
{
Create();
Delete(Head,"zhangsan");
Link *pNode = new Link;
pNode->age = 27;
strcpy_s(pNode->name,"Hello");
Insert(Head,pNode,1);
Show(Head);
cout<<"链表长:"<<Length(Head)<<endl;
return 0;
}