1.双向链表
双向链表是每个节点拥有两个指针域,分别指向该节点的前、后节点,因此,双向链表的数据读取具有双向性,更便于实现数据的修改。
双向链表的构造:
#include<iostream>
using namespace std;
struct DLNode
{
int data;
DLNode* next;//前导指针
DLNode* per;//后引指针
};
void creat(DLNode*& head)
{
DLNode* p, * temp;
head = (DLNode*)malloc(sizeof(DLNode));
head->next = NULL;
head->per = NULL;
p = head;
while (true)
{
temp = (DLNode*)malloc(sizeof(DLNode));
cin >> temp->data;
p->next = temp;
p->next->per = p;
p = temp;
}
p->next = NULL;
}
2.循环链表
循环链表的主要表示形式与单向链表类似,只是最后节点指针域不再为空,而是反过来指向首节点(有时会指向第二节点,保留头结点方便后续数据修改,请根据个人习惯进行使用。)
循环链表的创建:
#include<iostream>
using namespace std;
struct LNode
{
int data;
LNode* next;
};
void creat(LNode*& head)
{
LNode* p;
LNode* temp;
head = (LNode*)malloc(sizeof(LNode));
head->next = NULL;
p = head;
while (true)
{
temp = (LNode*)malloc(sizeof(LNode));
cin >> temp->data;
p->next = temp;
p = temp;
}
p->next = head;
}
3.链表的增删
链表不同于数组的一点就是链表的数据存储灵活性更高,因此在数据修改方面更加便利(数组增删需要移动带修改位置之后的全部数据,而链表修改只对待修改节点及它周围一个单位的节点有关)
①链表增加
链表数据增加实质上就是在原有链表基础上,在所需位置插入新节点。此时只需要让待插入位置前一节点的指针指向新节点,让新节点的指针域指向待插入位置的后一节点。具体操作如图:
例题:PTA 有序链表的归并
分别输入两个有序的整数序列(分别包含M和N个数据),建立两个有序的单链表,将这两个有序单链表合并成为一个有序单链表,并依次输出合并后的单链表数据。
输入格式:
测试数据有多组,处理到文件尾。对于每组测试,第一行输入M与N的值;第二行依次输入M个有序的整数;第三行依次输入N个有序的整数。
输出格式:
对于每组测试,输出合并后的单链表所包含的M+N个有序的整数。
输入样例:
6 5
1 23 26 45 66 99
14 21 28 50 100
2 2
1 2
1 3
输出样例:
1 14 21 23 26 28 45 50 66 99 100
1 1 2 3
具体代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define maxn 10100
using namespace std;
typedef struct ListNode
{
int data;
ListNode* next;
}LNode;
LNode* newlist(int n)
{
LNode* head;
head = (LNode*)malloc(sizeof(LNode));
head->next = NULL;
cin >> head->data;
n--;
LNode* mail = head;
while (n--)
{
LNode* p;
p = (LNode*)malloc(sizeof(LNode));
p->next = NULL;
cin >> p->data;
mail->next = p;
mail = p;
}
return head;
}
LNode* add(LNode* head1, LNode* head2, LNode* head3)
{
LNode* mail = head3;
while (head1 && head2)
{
if (head1->data < head2->data)
{
mail->next = head1;
mail = mail->next;
LNode* p;
p = head1;
head1 = head1->next;
p->next = NULL;
}
else
{
mail->next = head2;
mail = mail->next;
LNode* p;
p = head2;
head2 = head2->next;
p->next = NULL;
}
}
if (head1)
{
while (head1)
{
mail->next = head1;
mail = mail->next;
LNode* p = head1;
head1 = head1->next;
p->next = NULL;
}
}
else if (head2)
{
while (head2)
{
mail->next = head2;
mail = mail->next;
LNode* p = head2;
head2 = head2->next;
p->next = NULL;
}
}
return head3;
}
void print(LNode* head3)
{
int top = 1;
while (head3->next)
{
if (top)top = 0;
else printf(" ");
cout << head3->next->data;
head3 = head3->next;
}
cout << endl;
}
int main()
{
int m, n;
while (cin >> m >> n)
{
LNode* head1, * head2, * head3;
head1 = newlist(m);
head2 = newlist(n);
head3 = (LNode*)malloc(sizeof(LNode));
head3->next = NULL;
head3 = add(head1, head2, head3);
print(head3);
}
return 0;
}
②链表数据删除
数据删除可视为插入的逆操作,但要注意先让前一节点的指针域指向待删除节点后一节点,之后再将待删除节点指针清空,如果先清空指针,则后一节点地址会丢失,链表就此断裂。
具体操作如图:
具体练习博主还莫有找到,找到之后会再次更新(主要是电脑要没电了QAQ)