7-1 单链表的创建及遍历
读入n值及n个整数,建立单链表并遍历输出。
输入格式:
读入n及n个整数。
输出格式:
输出n个整数,以空格分隔(最后一个数的后面没有空格)。
输入样例:
在这里给出一组输入。例如:
2
10 5
输出样例:
在这里给出相应的输出。例如:
10 5
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *creat(int n)
{
int i;
struct node *head,*p,*tail;
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
tail=head;
for(i=0;i<n;i++)
{
p=(struct node*)malloc(sizeof(struct node));
scanf("%d",&p->data);
p->next=NULL;
tail->next=p;
tail=p;
}
return head;
}
void show(struct node *p)
{
while(p)
{
if(p->next!=NULL)printf("%d ",p->data);
else if(p->next==NULL)printf("%d\n",p->data);
p=p->next;
}
}
int main()
{
int n;
struct node *head;
scanf("%d",&n);
head=creat(n);
show(head->next);
return 0;
}
7-2 两个有序链表序列的合并
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 3 5 -1
2 4 6 8 10 -1
输出样例:
1 2 3 4 5 6 8 10
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node *Node;
struct Node
{
int data;
Node Next;
};
Node CList()
{
int d;
Node head = (Node)malloc(sizeof(struct Node)),q;
head -> Next = NULL;
q = head;
while(~scanf("%d",&d)&&d!=-1)
{
Node p = (Node)malloc(sizeof(struct Node));
p -> data = d;
p -> Next = NULL;
q -> Next = p;
q = p;
}
return head;
}
Node Merge(Node a,Node b)
{
a = a -> Next;
b = b -> Next;
Node head = (Node)malloc(sizeof(struct Node));
head -> Next = NULL;
Node q = head;
while(a || b)
{
Node p = (Node)malloc(sizeof(struct Node));
p -> Next = NULL;
if(a == NULL || a -> data > b -> data)
{
p -> data = b -> data;
b = b -> Next;
q -> Next = p;
q = p;
}
else
{
p -> data = a -> data;
a = a -> Next;
q -> Next = p;
q = p;
}
}
return head;
}
void printL(Node a)
{
a = a -> Next;
if(a == NULL)printf("NULL");
int flag = 0;
while(a)
{
if(flag)printf(" %d",a -> data);
else printf("%d",a -> data);
a = a -> Next;
flag = 1;
}
}
int main()
{
Node a = CList();
Node b = CList();
Node c = Merge(a,b);
printL(c);
}
7-3 两个有序链表序列的交集
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 2 5 -1
2 4 5 8 10 -1
输出样例:
2 5
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
}node;
struct node *createList();
int main()
{
//尾插法创建链表
node *L1 = createList();
node *L2 = createList();
int cnt = 0,num = 0;//num统计交集个数
node *p1 = L1;
node *p2 = L2;
while(p1!=NULL&&p2!=NULL)
{
if(p1->data<p2->data)
{
p1 = p1->next;
}
else if(p1->data == p2->data)
{//cnt为了规范输出
num++;
if(cnt == 0)
{
cnt = 1;
printf("%d",p1->data);
}
else
{
printf(" %d",p1->data);
}
p1 = p1->next;
p2 = p2->next;
}
else
{
p2 = p2->next;
}
}
if(num==0)
printf("NULL");
return 0;
}
struct node *createList()
{
node *head = NULL;
head = (node*)malloc(sizeof(node));
head->next = NULL;
node *p = head;
int x;
scanf("%d",&x);
while(x!= -1)
{
node *q =NULL;
q = (node*)malloc(sizeof(node));
q->data = x;
p->next = q;
p = q;
q->next = NULL;
//q->next = NULL是必要的,否则最后会使q指针
//指向一个未知空间,导致程序错误
scanf("%d",&x);
}
return head->next;
}
7-4 约瑟夫环
N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。
请按退出顺序输出每个退出人的原序号。
输入格式:
输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。
输出格式:
按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。
输入样例:
在这里给出一组输入。例如:
7 3
输出样例:
3 6 2 7 5 1 4
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *creat(int n)
{
struct node *head,*p,*tail;
int i;
p=(struct node*)malloc(sizeof(struct node));
p->data=1;
p->next=NULL;
head=tail=p;
for(i=2;i<=n;i++)
{
p=(struct node*)malloc(sizeof(struct node));
p->data=i;
p->next=NULL;
tail->next=p;
tail=p;
}
tail->next=head;
return (head);
}
int main()
{
int n,m;
struct node *head, *p,*q;
scanf("%d %d",&n,&m);
head=creat(n);
q=head;
while(q->next!=head)
{
q=q->next;
}
int con=0;
while(q->next!=q)
{
p=q->next;
con++;
if(con==m)
{
printf("%d ",p->data);
q->next=p->next;
free(p);
con=0;
}
else q=p;
}
printf("%d\n",q->data);
return 0;
}
7-5 链表去重
给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。
输入格式:
输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。
随后 N 行,每行按以下格式描述一个结点:
地址 键值 下一个结点
其中地址
是该结点的地址,键值
是绝对值不超过104的整数,下一个结点
是下个结点的地址。
输出格式:
首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。
输入样例:
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
输出样例:
00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<malloc.h>
#define N 100010
struct LNode {
int idex;//该节点的地址
int data;//该节点的数据
int nextidex;//下个节点的地址
struct LNode* next;
};
typedef struct LNode* List;
int main()
{
int a[N] = { 0 };//记录地址的data
int b[N] = { 0 };//记录重复
int c[N] = { 0 };//记录下一个地址
int n;//做循环
int m;//表头
int zb;//给b数组做定位
int cb;//给a数组做定位
int sb;//存data的
scanf("%d %d", &m, &n);
int i = 0;
for (i = 0; i < n; i++) {
scanf("%d %d %d", &zb, &sb, &cb);
a[zb] = sb;
c[zb] = cb;
// b[abs(sb)]++;
}
if (n == 1) {
printf("%05d %d -1", zb, sb);
return 0;
}
if (n == 0) {
return 0;
}
int aim = m;
List head, tail, p1, tou, wei;
//head为去重后的链表,tou为有重复的数字链表
//tail为去重后链表的尾指针,wei为有重复的数字的链表的尾指针
head = tail = p1 = tou = wei = NULL;
for (aim = m; aim != -1; aim = c[aim]) {
p1 = (List)malloc(sizeof(struct LNode));
p1->idex = aim;
p1->data = a[aim];
p1->nextidex = c[aim];//将该节点的内容扣在结构体上
if (b[abs(p1->data)]) {
if (tou == NULL) {
tou = p1;
}
else {
wei->next = p1;
wei->nextidex=p1->idex;
}
wei = p1;
}
else {
b[abs(p1->data)]++;
if (head == NULL) {
head = p1;
}
else {
tail->next = p1;
tail->nextidex=p1->idex;
}
tail = p1;
}
}
List L, l;
L = head;
l = L->next;
while (l) {//输出无重复的链表
printf("%05d %d %05d\n", L->idex, L->data, L->nextidex);
L = l;
l = l->next;
}
printf("%05d %d -1\n", L->idex, L->data);
L=tou;
l=L->next;
if (tou) {//输出重复的数字链表
while (l) {
printf("%05d %d %05d\n", L->idex, L->data, L->nextidex);
L = l;
l = l->next;
}
printf("%05d %d -1\n", L->idex, L->data);
}
}
7-6 带头节点的双向循环链表操作
本题目要求读入一系列整数,依次插入到双向循环链表的头部和尾部,然后顺序和逆序输出链表。
链表节点类型可以定义为
typedef int DataType;
typedef struct LinkedNode{
DataType data;
struct LinkedNode *prev;
struct LinkedNode *next;
}LinkedNode;
链表类型可以定义为
typedef struct LinkedList{
int length; /* 链表的长度 */
LinkedNode head; /* 双向循环链表的头节点 */
}LinkedList;
初始化链表的函数可声明为
void init_list(LinkedList *list);
分配节点的函数可声明为
LinkedNode *alloc_node(DataType data);
头部插入的函数可声明为
void push_front(LinkedList *list, DataType data);
尾部插入的函数可声明为
void push_back(LinkedList *list, DataType data);
顺序遍历的函数可声明为
void traverse(LinkedList *list);
逆序遍历的函数可声明为
void traverse_back(LinkedList *list);
输入格式:
输入一行整数(空格分隔),以-1结束。
输出格式:
第一行输出链表顺序遍历的结果,第二行输出逆序遍历的结果。
输入样例:
在这里给出一组输入。例如:
1 2 3 4 5 6 -1
输出样例:
5 3 1 2 4 6
6 4 2 1 3 5
#include<iostream>
using namespace std;
typedef int DataType;
typedef struct LinkedNode {
DataType data;
struct LinkedNode* prev;
struct LinkedNode* next;
}LinkedNode;
typedef struct LinkedList {
int length; /* 链表的长度 */
LinkedNode* head; /* 双向循环链表的头节点 */
}LinkedList;
void init_list(LinkedList* list)//初始化链表
{
list->length = 0;
list->head = new LinkedNode;
list->head->next = list->head;
list->head->prev = list->head;
}
LinkedNode* alloc_node(DataType d)//给节点分配内存空间
{
LinkedNode* L;
L = new LinkedNode;
L->data = d;
L->prev = NULL; L->next = NULL;
return L;
}
void push_front(LinkedList* list, DataType data)//头插法
{
LinkedNode* cur = alloc_node(data);
//当链表只有头结点时
if (list->head->next == list->head) {
list->head->next = cur;
cur->next = list->head;
cur->prev = list->head;
list->head->prev = cur;
}
else {
cur->next = list->head->next;//将新节点的next域指向原链表中头结点后面的节点
list->head->next->prev = cur;//然后将原头结点中后面节点prev域指向新节点;
cur->prev = list->head;//将新节点prev域指向头结点
list->head->next = cur;//将头结点的next域指向新节点
}list->length++;
}
void push_back(LinkedList* list, DataType data)//尾插法
{
LinkedNode* cur = NULL;
//如果链表内只有头结点
if (list->head->next == list->head) {
cur = alloc_node(data);
list->head->next = cur;
cur->prev = list->head;
cur->next = list->head;
list->head->prev = cur;
}//如果链表内有其他节点
else {
cur = alloc_node(data);
list->head->prev->next = cur;
cur->prev = list->head->prev;
list->head->prev = cur;
cur->next = list->head;
}list->length++;
}
void traverse(LinkedList* list)//顺序遍历
{
LinkedNode* cur = list->head->next;
//如果链表为空
if (list->length == 0) {}//啥也不用干
else {
for (int i = 0; i < list->length; i++) {
if( i != list->length-1)cout << cur->data << " ";
else cout << cur->data;
cur = cur->next;
} cout << endl;
}
}
void traverse_back(LinkedList* list)//倒序遍历
{
LinkedNode* cur = list->head->prev;
//如果链表为空
if (list->length == 0) {}
else {
for (int i = 0; i < list->length; i++) {
if( i != list->length-1)cout << cur->data << " ";
else cout << cur->data;
cur = cur->prev;
}cout << endl;
}
}
//自己增加的内容 销毁双向循环链表
void destroy(LinkedList* list)
{
LinkedNode* cur = list->head->next;
while (cur != list->head) {
LinkedNode* ret = cur;
cur = cur->next;
delete ret;
}delete(list->head);
}
int main() {
int data;
LinkedList L,*pHead=&L;
init_list(pHead);
int flag = 1;//根据输出结果可以观察得到构建链表时头插一次,尾插一次,以此类推
cin >> data;
while (data != -1)
{
if (flag)
{
push_front(pHead, data);
flag = 0;
}
else
{
push_back(pHead, data);
flag = 1;
}
cin >> data;
}
traverse(pHead);
traverse_back(pHead);
destroy(pHead);//销毁链表
return 0;
}
7-7 单链表就地逆置
输入多个整数,以-1作为结束标志,顺序建立一个带头结点的单链表,之后对该单链表进行就地逆置(不增加新结点),并输出逆置后的单链表数据。
输入格式:
首先输入一个正整数T,表示测试数据的组数,然后是T组测试数据。每组测试输入多个整数,以-1作为该组测试的结束(-1不处理)。
输出格式:
对于每组测试,输出逆置后的单链表数据(数据之间留一个空格)。
输入样例:
1
1 2 3 4 5 -1
输出样例:
5 4 3 2 1
#include<stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *creat()
{
struct node *head,*p,*tail;
int x;
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
tail=head;
while(scanf("%d",&x)&&x!=-1)
{
p=(struct node*)malloc(sizeof(struct node));
p->data=x;
p->next=NULL;
tail->next=p;
tail=p;
}
return (head);
}
void reverse(struct node *head)
{
struct node *p,*q;
p=head->next;
head->next=NULL;
q=p->next;
while(p!=NULL)
{
p->next=head->next;
head->next=p;
p=q;
if(q!=NULL)
{
q=q->next;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
struct node *head,*p;
head=creat();
reverse(head);
p=head->next;
while(p)
{
if(p->next==NULL)printf("%d\n",p->data);
else printf("%d ",p->data);
p=p->next;
}
}
return 0;
}
7-8 重排链表
给定一个单链表 L1→L2→⋯→Ln−1→Ln,请编写程序将链表重新排列为 Ln→L1→Ln−1→L2→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。
输入格式:
每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。
接下来有N行,每行格式为:
Address Data Next
其中Address
是结点地址;Data
是该结点保存的数据,为不超过105的正整数;Next
是下一结点的地址。题目保证给出的链表上至少有两个结点。
输出格式:
对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct point {
int next;
int data;
}point;
point p[1000002];//储存输入时的顺序
int a[1000002]; //储存链表顺序(只记录地址)
int b[1000002]; //排好后的顺序
int main() {
int n, begin,address;
cin >> begin >> n;
for (int i = 0; i < n; i++) {
cin >> address;
cin >> p[address].data >> p[address].next; //p现在储存的输入顺序
}
int h = 0;
while (begin != -1) {
a[h] = begin;
h++;
begin = p[begin].next;
} // a现在是链表状态
//别用n,用计数器h,n不一定是结点个数
int i = 0, j = h - 1,k=0;//双指针
for (int t = 0; t < h; t++) {
if (t % 2 == 0) {
b[k] = a[j];
k++;
j--;
}
else {
b[k] = a[i];
k++;
i++;
}
}
for (int i = 0; i < k-1; i++) {
printf("%05d %d %05d\n", b[i], p[b[i]].data, b[i+1]);
}
printf("%05d %d -1", b[k - 1], p[b[k-1]].data);
}//最后一个格式不一样,单独处理
7-9 头插法创建单链表、遍历链表、删除链表
#include<stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *creat( )
{
struct node *head,*p;
int a;
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
while(scanf("%d",&a)&&a!=-1)
{
p=(struct node*)malloc(sizeof(struct node));
p->data=a;
p->next=head->next;
head->next=p;
}
return head;
}
void DeleteLink(struct node *head)
{
struct node *p;
while(head->next)
{
p=head->next;
head->next=p->next;
free(p);
}
}
int main()
{
struct node *head,*p;
int k;
scanf("%d",&k);
while(k--){
head=creat();
p=head->next;
while(p)
{
if(p->next==NULL)printf("%d ",p->data);
else printf("%d ",p->data);
p=p->next;
}
printf("\n");
DeleteLink(head);
}
return 0;
}
7-9 头插法创建单链表、遍历链表、删除链表
输入一系列自然数(0和正整数),输入-1时表示输入结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。
输入格式:
第一行是一个正整数k,表示以下会有k组测试数据。
每组测试数据是一系列以空格隔开的自然数(0和正整数)。数列末尾的 -1 表示本组测试数据结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。
输出格式:
对于每组测试数据,输出链表中各节点的数据域。每个数据后有一个空格。每组测试数据的输出占1行。
输入样例:
3
1 2 3 4 5 -1
30 20 10 -1
4 2 2 1 1 2 0 2 -1
输出样例:
在这里给出相应的输出。例如:
5 4 3 2 1
10 20 30
2 0 2 1 1 2 2 4
注意:对每组测试数据,创建链表,遍历链表输出之后,一定要删除链表,否则会出现“内存超限”。
#include<stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *creat( )
{
struct node *head,*p;
int a;
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
while(scanf("%d",&a)&&a!=-1)
{
p=(struct node*)malloc(sizeof(struct node));
p->data=a;
p->next=head->next;
head->next=p;
}
return head;
}
void DeleteLink(struct node *head)
{
struct node *p;
while(head->next)
{
p=head->next;
head->next=p->next;
free(p);
}
}
int main()
{
struct node *head,*p;
int k;
scanf("%d",&k);
while(k--){
head=creat();
p=head->next;
while(p)
{
if(p->next==NULL)printf("%d ",p->data);
else printf("%d ",p->data);
p=p->next;
}
printf("\n");
DeleteLink(head);
}
return 0;
}