http://codeup.cn/problem.php?cid=100000660&pid=9
题目描述
双向链表是在结点中既保存了后一个结点指针又保存了前一个结点指针的链表。这种链表较单向链表而言能够快速查找某一结点的前后结点。下面给出双向链表的定义、插入以及删除算法描述。
图1:双向链表示例
(a)结点结构;(b)空的双向循环链表;(c)含有三个结点的双向循环链表
图2:双向链表的定义以及创建
双向链表在插入与删除时一定要注意其操作步骤的顺序。下面给出双向链表在插入与删除时的图示。
图3:双向链表插入与删除的图示
(a)双向链表的删除操作;(b)双向链表的插入操作
图4:双向链表的查找以及插入
图5:双向链表的删除操作
输入
输入数据只有一组,包含很多行。每行有1~3个整数。第一个整数如果是0,则表示输出双向链表中的所有元素;第一个整数如果是1,表示插入1个整数,其后跟2个整数i、e代表在第i个位置插入e;第一个整数如果是2,表示删除1个整数,其后跟1个整数i,表示删除的位置为i。
起始双向链表为空表。保证链表中每个元素不会重复,同时所有的操作都合法。
输出
当需要输出双向链表中的所有元素时输出,每次输出一行。整数间用一个空格隔开。
样例输入
1 1 2
0
1 2 7
0
2 1
0
1 2 4
1 3 5
1 2 6
0
2 3
0
样例输出
2
2 7
7
7 6 4 5
7 6 5
提示
提示:
1、如果使用switch,注意每个case后面使用break。
2、结构体定义时,因为定义里面有用到这个类型的指针,所以需要在开始struct后面写上结构体名。
3、注意循环链表全部遍历结束的条件是遍历的指针是否又指向了头结点。
总结:
1、双向链表的重要之处在于插入和删除时的操作顺序,切勿弄乱顺序而丢失数据。
2、循环链表全部遍历的结束条件需要注意,不是非空,而是判断是否到头结点了。
本题考查的是双向循环链表,所以上述都需要注意。
#include<iostream>
using namespace std;
#include<string.h>
typedef struct Dlnode {
int data;
Dlnode *prior;
Dlnode *next;
}Dlnode;
void Show(Dlnode *C)
{
Dlnode *p = C->next;
printf("%d", p->data);
while (p->next != C)
{
p = p->next;
printf(" %d", p->data);
}
putchar('\n');
}
Dlnode *Locate(Dlnode *C, int n)
{
int j = 0; Dlnode *p = C;
while (j < n&&p->next != C)
{
p = p->next;
j++;
}
if (j < n&&p->next == C)
return NULL;
return p;
}
void Insert(Dlnode *C, int n, int e)
{
Dlnode *p = Locate(C, n);
Dlnode *s;
s = (Dlnode*)malloc(sizeof(Dlnode));
s->data = e;
if (p)
{
s->next = p;
s->prior = p->prior;
p->prior->next = s;
p->prior = s;
}
else
{
s->next = C;
s->prior = C->prior;
C->prior->next = s;
C->prior = s;
}
}
void Delete(Dlnode *C, int n)
{
Dlnode *p = Locate(C, n);
p->next->prior = p->prior;
p->prior->next = p->next;
free(p);
}
int main()
{
int n, m, e; Dlnode *C;
C = (Dlnode*)malloc(sizeof(Dlnode));
C->next = C;
C->prior = C;
while (scanf("%d", &n))
{
switch (n)
{
case 0:
Show(C); break;
case 1:
scanf("%d%d", &m, &e);
Insert(C, m, e); break;
case 2:
scanf("%d", &m);
Delete(C, m); break;
}
}
return 0;
}