链表图解(双向、循环链表+链表增删)

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)

上一篇:使用Logstash将日志导入OSS


下一篇:考研数据结构(九):单链表排序(直接插入排序、冒泡排序、选择排序)