代码参考《妙趣横生的算法.C语言实现》、《剑指OFFER 名企面试官精讲典型编程题 第2版》等
前言
本章总结在看书过程中的一些关于顺序表的算法题并可能含有一些自己的一些疑问。题目数量不定,随阅历增加而增加;
1、合并两个顺序表
题目要求:
有两个顺序存储的线性表,分别存放了一些整数数据,每个顺序表中存放的数据从小到大排列。写一个程序,将两个表合并,生成一个新的顺序表,里面的顺序仍然按照从小到大排列。
例如:
list1:1,2,4,8,10
list2:3,9,11
合并之后的list3:1,2,3,4,8,9,10,11
提示:应该使用动态创建这个顺序表,这样list3的长度才可以根据list1和list2的长度动态调整。
要实现两个顺序按值归并,最终仍保持数据的从小到大递增排序,可以设置两个指针p1、p2分别指向两个待合并的顺序表list1和list2,设置指针p3指向新表list3用来向list3中存放数据,然后逐一比较p1和p2指向的内容 ,将其中较小的那个放到p3指向的list3的存储单元,然后将较小的那个指针+1.使其指向表的下一个数据,同时p3也要自动+1。重复上述操作,直到list1,list2中某一个顺序表的内容被全部归并到list3中.最后再将未完全归并的顺序表中的后续内容整体移至list3中。
代码:
#include <stdio.h>
#include <stdlib.h>
#include "malloc.h"
#include "conio.h"
typedef int ElemType;
typedef struct {
int* elem;
int length;
int listsize;
}Sqlist;
//初始化顺序表
void InitSqlist(Sqlist *L,int size)
{
L->elem = (int*)malloc(sizeof(ElemType)*size); //在堆内存上开辟空间,并将地址指针传给elem
if (!L->elem)
{
printf("顺序表内存开辟失败");
exit(0);
}
L->length = 0; //最开始的表长0
L->listsize = size;
}
//向顺序表中插入元素
//向顺序表L第i个位置插入元素item
void InsertElem(Sqlist* L,int i, ElemType item)
{
//追加内存后的新的基址、指向插入位置的指针、移动数据的指针中间变量
ElemType* base, * insertPtr, * p;
if (i<1 || i>L->length + 1)
{
printf("非法插入");
exit(0);
}
if (L->length >= L->listsize) //顺序表的空间不够,追加内存
{
base = (ElemType*)realloc(L->elem, (L->listsize + 10) * sizeof(ElemType)); //将追加内容后的内存首地址传给base
L->elem = base;
L->listsize = L->listsize + 100;
}
insertPtr = &(L->elem[i-1]); //指针指向插入位置
for (p = &L->elem[L->length - 1];p >= insertPtr;p--)
{
//移动顺序表中数据
*(p+1) = *p;
}
*insertPtr = item; //插入数据元素
L->length++;
}
//销毁顺序表
void DestroySqlist(Sqlist* list)
{
int* p = list->elem;
free(p);
list->elem = NULL;
list->length = 0;
list->listsize = 0;
}
//两个顺序表内容的合并,返回一个新的list
Sqlist MergeList(Sqlist list1, Sqlist list2)
{
//将list1和list2的内容合并到list3并返回
int* p1, * p2, * p3, * p1_last, * p2_last;
Sqlist list3;
p1 = list1.elem; //p1指向list1第一个元素
p2 = list2.elem; //p2指向list2第一个元素
//初始化list3,其长度为list1 list2 长度之和
InitSqlist(&list3,list1.length+list2.length);
p3 = list3.elem; //p3指向list3第一个元素
p1_last = list1.length + list1.elem - 1; //p1_last指向list1的表尾
p2_last = list2.length + list2.elem - 1; //p2_last指向list2的表尾
//实现合并
while (p1<=p1_last && p2<=p2_last) //当list1与list2中有一个list被遍历完
{
if (*p1 <= *p2) //当p1指向的元素小于p2指向的元素
{
*p3 = *p1;
p3++;
p1++;
}
else
{
*p3 = *p2;
p3++;
p2++;
}
list3.length++;
}
//将list1或者list2中剩余元素并入list3中
if (p1 <= p1_last) //p1有剩余
{
while (p1 <= p1_last)
{
*p3 = *p1;
p3++;
p1++;
list3.length++;
}
}
else
{
while (p2 <= p2_last)
{
*p3 = *p2;
p3++;
p2++;
list3.length++;
}
}
//当搬移完成后,返回list3
return list3;
}
//测试程序
int main()
{
Sqlist list1, list2, list3; //实例化3个顺序表
int n, i; //存放list长度中间变量、累加器
ElemType e; //插入元素中间变量
printf("请输入list1的长度\n");
scanf("%d",&n);
InitSqlist(&list1,n);
printf("请输入list1的元素\n");
for (i=1;i<=n;i++)
{
scanf("%d",&e);
InsertElem(&list1,i,e);
}
printf("请输入list2的长度\n");
scanf("%d", &n);
InitSqlist(&list2, n);
printf("请输入list2的元素\n");
for (i = 1;i <= n;i++)
{
scanf("%d", &e);
InsertElem(&list2, i, e);
}
list3 = MergeList(list1,list2);
printf("输出合并后的结果\n");
for (i = 0;i < list3.length;i++)
{
printf("%d ",list3.elem[i]); //这里%d根据ElemType类型来进行修改
}
//销毁list,释放内存
DestroySqlist(&list1);
DestroySqlist(&list2);
DestroySqlist(&list3);
_getche();
return 0;
}
效果: