题目
设计一个算法,将一个头结点为A的单链表(其数据域为整数)分解成两个单链表A和B.使得A链表只含有原来链表中data 域为奇数的结点,而B链表只含有原链表中data城为偶数的结点,且保持原来的相对顺序。
分析
解决思路为:用指针p从头至尾扫描A链表,当发现结点data域为偶数的结点则取下,插入链表B中。因为题目要求保持原来数据元素的相对顺序,所以要用尾插法来建立B链表。
核心代码如下:
/* 将A链表中的奇数和偶数分离出来,奇数继续保留在A链表中,偶数保留在B链表中 */
/* *A指的是要处理的单链表;*&B指的是要保存偶数的新链表 */
void sepEvenAndOdd(LNode *A,LNode *&B) {
LNode *tempA=A->next;// 开始结点
LNode *pre=A;// 保存A链表的头结点(其实是保存的是前驱结点)
B=(LNode *)malloc(sizeof(LNode)); // 创建B链表
B->next=NULL;
LNode *tempB=B; // 保存B链表的头结点(其实是尾指针结点)
LNode *tempDelNode; // 临时保存删除结点
while(tempA!=NULL) { // 循环A链表
if(tempA->data%2!=0) { // 判断A链表中的结点的data值是奇数还是偶数
pre=tempA;// 如果是奇数,将前驱结点置为当前结点
tempA=tempA->next; // 并且到下一个结点去
} else { // 如果是偶数
tempDelNode=tempA;// 临时保存要删除的结点,即偶数结点
pre->next=tempDelNode->next;// 连接A链表,删除偶数结点
tempA=tempA->next; // A链表继续遍历到下一个结点
tempB->next=tempDelNode; // 将偶数结点链接到B链表上
tempB=tempDelNode;// 将B链表的尾结点置为当前新添加的结点
}
}
tempB->next=NULL;// 注意:需将添加结点成功的B链表终端节点的next置为NULL
}
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
// 声明单链表结构体
struct LNode {
int data;
struct LNode *next;
};
/* 通过用户输入数据创建一个单链表,由用户输入整型测试数据 */
/* 返回一个单链表 */
LNode * createList() {
LNode *head;
LNode *p1,*p2;
p1=p2=(LNode *)malloc(sizeof(LNode));
head=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
int i=0;
while(p1->data!=0) { // 当用户在控制台输入0时结束循环
i+=1;
if(i==1) {
head->next=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
}
p2->next=NULL;
return head;
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
LNode *temp=list->next;// 单链表的开始结点
printf("\n");
while(temp!=NULL) { // 循环单链表
printf("%ld\t",temp->data); // 打印单链表中的data数据
temp=temp->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 将A链表中的奇数和偶数分离出来,奇数继续保留在A链表中,偶数保留在B链表中 */
/* *A指的是要处理的单链表;*&B指的是要保存偶数的新链表 */
void sepEvenAndOdd(LNode *A,LNode *&B) {
LNode *tempA=A->next;// 开始结点
LNode *pre=A;// 保存A链表的头结点(其实是保存的是前驱结点)
B=(LNode *)malloc(sizeof(LNode)); // 创建B链表
B->next=NULL;
LNode *tempB=B; // 保存B链表的头结点(其实是尾指针结点)
LNode *tempDelNode; // 临时保存删除结点
while(tempA!=NULL) { // 循环A链表
if(tempA->data%2!=0) { // 判断A链表中的结点的data值是奇数还是偶数
pre=tempA;// 如果是奇数,将前驱结点置为当前结点
tempA=tempA->next; // 并且到下一个结点去
} else { // 如果是偶数
tempDelNode=tempA;// 临时保存要删除的结点,即偶数结点
pre->next=tempDelNode->next;// 连接A链表,删除偶数结点
tempA=tempA->next; // A链表继续遍历到下一个结点
tempB->next=tempDelNode; // 将偶数结点链接到B链表上
tempB=tempDelNode;// 将B链表的尾结点置为当前新添加的结点
}
}
tempB->next=NULL;// 注意:需将添加结点成功的B链表终端节点的next置为NULL
}
int main() {
/* [0.]创建初始测试单链表 */
LNode *list,*list2;
list=createList();// 创建测试链表
list2=list;
printList(list);// 打印单链表
sepEvenAndOdd(list,list2);// 分离奇数偶数链表
printList(list); // 打印奇数链表
printList(list2);// 打印偶数链表
return 0;
}
运行结果如下:
扩展
下面是关于求一个链表中奇数和偶数的。
分离链表中的奇数留下偶数:
/* 分离奇数结点,得到全是偶数结点的链表 */
void sepOdd(LNode *A){
LNode *temp=A->next;// 开始结点
LNode *pre=A;// 头结点(直接前驱)
LNode *tempDelNode;// 临时保存被删除结点
while(temp!=NULL){
if(temp->data%2==0){
pre=temp;
temp=temp->next;
}else{
tempDelNode=temp;
pre->next=tempDelNode->next;
temp=temp->next;
free(tempDelNode);
}
}
}
分离链表中的偶数留下奇数:
/* 分离偶数结点,得到全是奇数结点的链表 */
void sepEven(LNode *A){
LNode *temp=A->next;// 开始结点
LNode *pre=A;// 直接前驱
LNode *tempDelNode;
while(temp!=NULL){
if(temp->data%2!=0){
pre=temp;
temp=temp->next;
}else{
tempDelNode=temp;
pre->next=tempDelNode->next;
temp=temp->next;
free(tempDelNode);
}
}
}
测试代码如下:
#include <stdio.h>
#include <stdlib.h>
// 声明单链表结构体
struct LNode {
int data;
struct LNode *next;
};
/* 通过用户输入数据创建一个单链表,由用户输入整型测试数据 */
/* 返回一个单链表 */
LNode * createList() {
LNode *head;
LNode *p1,*p2;
p1=p2=(LNode *)malloc(sizeof(LNode));
head=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
int i=0;
while(p1->data!=0) { // 当用户在控制台输入0时结束循环
i+=1;
if(i==1) {
head->next=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
}
p2->next=NULL;
return head;
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
LNode *temp=list->next;// 单链表的开始结点
printf("\n");
while(temp!=NULL) { // 循环单链表
printf("%ld\t",temp->data); // 打印单链表中的data数据
temp=temp->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 分离偶数结点,得到全是奇数结点的链表 */
void sepEven(LNode *A){
LNode *temp=A->next;// 开始结点
LNode *pre=A;// 直接前驱
LNode *tempDelNode;
while(temp!=NULL){
if(temp->data%2!=0){
pre=temp;
temp=temp->next;
}else{
tempDelNode=temp;
pre->next=tempDelNode->next;
temp=temp->next;
free(tempDelNode);
}
}
}
/* 分离奇数结点,得到全是偶数结点的链表 */
void sepOdd(LNode *A){
LNode *temp=A->next;// 开始结点
LNode *pre=A;// 头结点(直接前驱)
LNode *tempDelNode;// 临时保存被删除结点
while(temp!=NULL){
if(temp->data%2==0){
pre=temp;
temp=temp->next;
}else{
tempDelNode=temp;
pre->next=tempDelNode->next;
temp=temp->next;
free(tempDelNode);
}
}
}
int main() {
/* [0.]创建初始测试单链表 */
LNode *list,*list2;
list=createList();// 创建测试链表
printList(list);// 打印单链表
sepEven(list);// 分离偶数
printList(list);// 打印全是奇数的链表
list2=createList();
printList(list2);
sepOdd(list2);// 分离奇数
printList(list2);// 打印全是偶数的链表
return 0;
}
结果如下:
分离顺序表的奇数和偶数
分离的核心代码如下:
/* 分离奇数,留下全是偶数的顺序表 */
/* &list指的是要被分离的顺序表 */
void sepOdd(SqlList &list){
int i=0;// 计数器,记录当前是第几个数
while(i<list.length){
if(list.a[i]%2!=0){ // 判断是否是偶数
// 如果不是偶数则删除顺序表中的奇数
for(int m=i;m<list.length-1;m++){ // 将奇数后的所有数向前移动一个位置
list.a[m]=list.a[m+1];
}
list.length--;// 顺序表长度减1
}else{// 如果是奇数的话,则保留在顺序表中,继续判断下一个数
i++;// 计数器+1
}
}
}
/* 分离偶数,留下全是奇数的顺序表 */
/* &list指的是要被分离的顺序表 */
void sepEven(SqlList &list){
int i=0;// 计数器
while(i<list.length){
if(list.a[i]%2==0){
for(int m=i;m<list.length-1;m++){
list.a[m]=list.a[m+1];
}
list.length--;
}else{
i++;
}
}
}
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#define maxSize 20
typedef struct SqlList {
int a[maxSize];
int length;
} SqlList;
/* 创建顺序表 */
void createList(SqlList &L) {
int tempNo = 1;
int tempData = 0;
do {
printf("请输入顺序表第%d个元素:",tempNo);
scanf("%d",&tempData);
if(tempData!=-1) {
L.a[tempNo-1] = tempData;
L.length = tempNo;
tempNo++;
}
} while(tempNo<=maxSize&&tempData!=-1);
}
/* 打印顺序表 */
void printSqlList(SqlList list) {
printf("\n");
for(int i=0; i<list.length; i++) {
printf("%d\t",list.a[i]);
}
printf("\n");
}
/* 分离奇数,留下全是偶数的顺序表 */
/* &list指的是要被分离的顺序表 */
void sepOdd(SqlList &list){
int i=0;// 计数器,记录当前是第几个数
while(i<list.length){
if(list.a[i]%2!=0){ // 判断是否是偶数
// 如果不是偶数则删除顺序表中的奇数
for(int m=i;m<list.length-1;m++){ // 将奇数后的所有数向前移动一个位置
list.a[m]=list.a[m+1];
}
list.length--;// 顺序表长度减1
}else{// 如果是奇数的话,则保留在顺序表中,继续判断下一个数
i++;// 计数器+1
}
}
}
/* 分离偶数,留下全是奇数的顺序表 */
/* &list指的是要被分离的顺序表 */
void sepEven(SqlList &list){
int i=0;// 计数器
while(i<list.length){
if(list.a[i]%2==0){
for(int m=i;m<list.length-1;m++){
list.a[m]=list.a[m+1];
}
list.length--;
}else{
i++;
}
}
}
int main() {
SqlList list,list2;// 声明一个顺序表
createList(list); // 创建顺序表
printSqlList(list);// 打印创建成功的顺序表
sepOdd(list);// 分离奇数留下偶数列表
printSqlList(list);// 打印偶数顺序表
createList(list2); // 创建顺序表
printSqlList(list2);// 打印创建成功的顺序表
sepEven(list2);// 分离偶数留下奇数列表
printSqlList(list2);// 打印奇数顺序表
return 0;
}
结果如下: