习题1:
已知两个链表A和B分别表示两个集合,其元素递增排列。请设计一个算法,求出A与B的交集,并将结果存放在A链表中。
【分析】当看到这道题目时,我们一般会想到对两个链表进行遍历,将每个链表的元素依次比较,最后将相同的元素存放在A链表中。但是,若A链表中有n个元素,B链表中有n个元素,这种算法的时间复杂度为O(n^2)。时间复杂度过高,并且,此时我们忽略了题目中的已知条件(元素递增排列)。
现在,我们使用“元素递增排列”这一个关键的要素,可以分析出,一旦A链表中指针正在指向元素小于B链表中指针正在指向的元素,则A链表中的这个元素不可能再与B元素中该指针指向的元素及其后链接的元素相等。
顺次比较,得到目标链表。
SLTNode* SLTIntersect(SLTNode** list1,SLTNode** list2){
//cur1依次指向链表A的每一个节点,cur2依次指向链表B的每一个节点
SLTNode *cur1=*list1, *cur2=*list2;
//dst_head 是目标链表的头节点(便于返回)
//dst_tail是目标链表的尾节点(便于尾插交集元素的节点)
SLTNode *dst_head=NULL,*dst_tail=NULL;
//当链表A或者链表B中的任意一个链表被遍历结束,循环结束
while(cur1&&cur2){
//链表A中的元素小于链表B中的元素,删除链表A中的该节点
if(cur1->data<cur2->data)
{
SLTNode* tmp=cur1;
cur1=cur1->next;
free(tmp);
}
//链表B中的元素小于链表A中的元素,删除链表B中的该节点
else if(cur2->data<cur1->data){
SLTNode* tmp=cur2;
cur2=cur2->next;
free(tmp);
}
//链表A中的元素等于链表B中的元素,将该节点尾插到目标链表
else if (cur1->data==cur2->data){
//若目标链表为空
if(dst_head==NULL){
dst_head=dst_tail=cur1;
}
//若目标链表不为空
else{
dst_tail->next=cur1;
dst_tail=dst_tail->next;
}
//删除链表A中的该节点
SLTNode* tmp1=cur1;
cur1=cur1->next;
free(tmp1);
//删除链表B的该节点
SLTNode* tmp2=cur2;
cur2=cur2->next;
free(tmp2);
}
}
//若链表A未被遍历完,释放A中的所有节点
while(cur1){
SLTNode* tmp=cur1;
cur1=cur1->next;
free(tmp);
}
//若链表B未被遍历完,释放B中的所有节点
while(cur2){
SLTNode* tmp=cur2;
cur2=cur2->next;
free(tmp);
}
//为目标链表结尾
dst_tail->next=NULL;
//将目标函数的头节点赋给链表A的头节点
*list1=dst_head;
return *list1;
}
进行测试:(使用Dev C++)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode {
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead) {
SLTNode* cur = phead;
while (cur) {
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuySLTNode(SLTDataType x) {
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL) {
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL) {
*pphead = newnode;
}
else {
//找尾
SLTNode* tail = *pphead;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = newnode;
}
}
SLTNode* SLTIntersect(SLTNode** list1,SLTNode** list2){
SLTNode *cur1=*list1, *cur2=*list2;
SLTNode *dst_head=NULL,*dst_tail=NULL;
while(cur1&&cur2){
if(cur1->data<cur2->data)
{
SLTNode* tmp=cur1;
cur1=cur1->next;
free(tmp);
}
else if(cur2->data<cur1->data){
SLTNode* tmp=cur2;
cur2=cur2->next;
free(tmp);
}
else if (cur1->data==cur2->data){
if(dst_head==NULL){
dst_head=dst_tail=cur1;
}
else{
dst_tail->next=cur1;
dst_tail=dst_tail->next;
}
SLTNode* tmp1=cur1;
cur1=cur1->next;
free(tmp1);
SLTNode* tmp2=cur2;
cur2=cur2->next;
free(tmp2);
}
}
while(cur1){
SLTNode* tmp=cur1;
cur1=cur1->next;
free(tmp);
}
while(cur2){
SLTNode* tmp=cur2;
cur2=cur2->next;
free(tmp);
}
dst_tail->next=NULL;
*list1=dst_head;
return *list1;
}
int main() {
SLTNode* list1 = NULL;
SLTPushBack(&list1, 1);
SLTPushBack(&list1, 3);
SLTPushBack(&list1, 4);
SLTPushBack(&list1, 5);
SLTPushBack(&list1, 8);
SLTNode* list2=NULL;
SLTPushBack(&list2, 3);
SLTPushBack(&list2, 4);
SLTPushBack(&list2, 4);
SLTPushBack(&list2, 6);
SLTPrint(list1);
SLTPrint(list2);
SLTIntersect(&list1,&list2);
SLTPrint(list1);
return 0;
}
运行结果:
习题2:
设计算法将一个带头节点的单链表分解为两个具有同样结构的链表B和C,其中B表的节点为A表中值小于0的节点,C表的节点为A表中值大于0 的节点(链表A中的元素为非零整数,要求B、C表利用A表的节点)。
【分析】对A中的节点依次进行比较,若小于0则将节点尾插到B表中,若大于0则将节点尾插到A表中。
void SLTPartiton(SLTNode* phead) {
SLTNode* lGuard = BuySLTNode(0);
SLTNode* lTail = lGuard;
SLTNode* gGuard = BuySLTNode(0);
SLTNode* gTail = gGuard;
gTail->next = lTail->next = NULL;
SLTNode* cur = phead;
while (cur) {
if (cur->data < 0)
{
lTail->next = cur;
lTail = lTail->next;
}
else {
gTail->next = cur;
gTail = gTail->next;
}
cur = cur->next;
}
lTail->next = NULL;
gTail->next = NULL;
SLTPrint(lGuard->next);
SLTPrint(gGuard->next);
}
运行测试:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode {
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead) {
SLTNode* cur = phead;
printf("head->");
while (cur) {
printf("(%d)->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuySLTNode(SLTDataType x) {
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL) {
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL) {
*pphead = newnode;
}
else {
//找尾
SLTNode* tail = *pphead;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = newnode;
}
}
void SLTPartiton(SLTNode* phead) {
SLTNode* lGuard = BuySLTNode(0);
SLTNode* lTail = lGuard;
SLTNode* gGuard = BuySLTNode(0);
SLTNode* gTail = gGuard;
gTail->next = lTail->next = NULL;
SLTNode* cur = phead;
while (cur) {
if (cur->data < 0)
{
lTail->next = cur;
lTail = lTail->next;
}
else {
gTail->next = cur;
gTail = gTail->next;
}
cur = cur->next;
}
lTail->next = NULL;
gTail->next = NULL;
SLTPrint(lGuard->next);
SLTPrint(gGuard->next);
}
int main() {
SLTNode* list1 = BuySLTNode(0);
SLTPushBack(&list1, 1);
SLTPushBack(&list1, 9);
SLTPushBack(&list1, -4);
SLTPushBack(&list1, 5);
SLTPushBack(&list1, -8);
SLTPrint(list1->next);
SLTPartiton(list1);
return 0;
}
结果如下: