参考书籍:数据结构(C语言版)--严蔚敏(清华大学出版社)
最近在学数据结构,选用以上参考数据,书中的例子只是一个编程参考,并不能直接使用,这里我给出完整实例(编程
思想与书本保持一致)。
实际问题1:假设利用两个线性表LA和LB分别表示两个集合A和B(即线性表中的数据元素即为集合中的成员),现要求
一个新的集合A=A U B(并运算)。这就要求:扩大线性表LA,将存在于线性表LB中而不存在与线性表LA中的数据元素
插入到线性表LA中去。--只要从线性表LB中依次取得每个数据元素,并依值在线性表LA中进行查访,若不存在则插入之。
实际问题2:已知线性表LA和LB的数据元素按值非递减有序排列,现在要求将LA和LB并为一个新的线性表LC,且LC中的
数据元素仍按值非递减有序排列。
实际问题1用算法函数1解决,实际问题2用算法函数2解决,因为两个问题用到的函数很多是一样的,所以写在一个程序文件中。
其中:需要注意易错点:
(1)插入操作函数输入的插入位置是位序,不是数组下标,并且是插入到位序之前,如果要在位序之后,必须再加1(记得输入合法性判断)
(2)插入操作函数不可以对空表进行操作,因为L.length不能为0,至少为1,也就是需要一个函数来初始化线性表第一个元素
(3)元素定位函数必须对端点值进行单独判断
(4)插入操作函数和删除操作函数都是复杂度比较高的操作,因为涉及后续所有元素的向前/向后移位,效率比较低
(5)对于线性表(如数组)的指针操作更快捷,但是记得次数判断时多使用末尾元素指针作为循环终止条件
(6)合并已排序线性表函数ListMergeOrder_better使用指针操作,用复制代替ListMergeOrder函数的插入操作(需要遍历),效率更高
#include
using namespace std;
#define Size_InitList 100
#define Increment_List 10
int la[Size_InitList] = { 1, 2, 6, 7 };
int lb[Size_InitList] = { 4, 5, 6, 7, 8, 9, 10, 11 };
typedef struct{
int* elem;
int length;
int listsize;
}Sqlist;
void ListInit(Sqlist &L);
int ListFirstDataInit(Sqlist &L, int ListFirstData);
int ExistenceElem(Sqlist L, int e);
int ListInsert(Sqlist &L, int i, int insertdata);
int ListDelete(Sqlist &L, int i, int &deletedata);
void ListDisplay(Sqlist L);
void UnionList(Sqlist &La, Sqlist Lb);
void ListMergeOrder(Sqlist &Lc, Sqlist La, Sqlist Lb);
void ListMergeOrder_better(Sqlist &Lc, Sqlist La, Sqlist Lb);
int main(){
Sqlist La, Lb, Lc;
ListInit(La);
ListInit(Lb);
ListInit(Lc);
for (int i = 0; i < 4; i++){
if (i == 0){
ListFirstDataInit(La,la[i]);
}
ListInsert(La, i + 1, la[i]);//插到第i个元素之后,为i+1
}
for (int i = 0; i < 8; i++){
if (i == 0){
ListFirstDataInit(Lb, lb[i]);
}
ListInsert(Lb, i + 1, lb[i]);
}
/*******解题算法1:合并线性表La和Lb(相同元素不重复)*********/
//UnionList(La,Lb);
//ListDisplay(La);
/*******解题算法2:合并线性表La和Lb(相同元素重复),并且重新排序********/
ListMergeOrder_better(Lc, La, Lb);
ListDisplay(Lc);
return 0;
}
void ListInit(Sqlist &L){
L.elem = (int*)malloc(Size_InitList*sizeof(int));
if (!L.elem){
cout << "Memory allocation fail!" << endl;
exit(1);
}
L.length = 0;
L.listsize = Size_InitList;
}
int ListFirstDataInit(Sqlist &L, int ListFirstData){
L.elem[0] = ListFirstData;
return 0;
}
/************************************ ListInsert ***********************************
//线性表元素插入
//第一:线性表不能为空(无法初始化第一个元素,因为L.length不能为0);
//第二:这里的i是位序,如果插到第i元素前则为i,如果插到第i元素后则为i+1
//第三:时间复杂度:O(L.length)
*/
int ListInsert(Sqlist &L, int i, int insertdata){
if (i<1 || i>L.length + 1){//L.length+1:可以插入到最后一个元素的后面
cout << "InserList input error!" << endl;
return 0;
}
if (L.length >= L.listsize){
int* newbase = (int*)realloc(L.elem, (L.listsize + Increment_List)*sizeof(int));
if (!newbase){//分配失败
exit(1);
}
L.elem = newbase;
L.listsize += Increment_List;
}
int* remark = &L.elem[i - 1];//注意:remark所指的元素是开始往后移动的元素,所以p>=remark取到等号
int* p = &L.elem[L.length - 1];
for (; p >= remark; p--){
*(p + 1) = *p;
}
*remark = insertdata;
++L.length;
return 0;
}
/******************************** ListDelete ******************************************
//线性表元素删除
//时间复杂度:O(L.length)
*/
int ListDelete(Sqlist &L, int i, int &deletedata){
if (i<1 || i>L.length){
cout << "ListDelete:ListDelete Input error!" << endl;
return 0;
}
int* last = &L.elem[L.length - 1];
int* p = &L.elem[i - 1];
deletedata = *p;
for (; p < last; p++){
*p = *(p + 1);
}
--L.length;
return 0;
}
void ListDisplay(Sqlist L){
for (int i = 0; i < L.length; i++){
cout << L.elem[i] << ' ';
}
cout << endl;
}
/******************************* ExistenceElem *******************************************
//判断线性表中元素的存在性
//查找L中是否存在元素e,不存在返回0,否则返回非0值(返回位序);
//时间复杂度:O(L.length)
*/
int ExistenceElem(Sqlist L, int e){
for (int i = 0; i < L.length; i++){
if (L.elem[i] == e){
return i + 1;
}
}
return 0;
}
int ElemLocate(Sqlist L, int elem){//e为要查找的元素,函数返回实际要插入的位序
if (elem <= L.elem[0]){//端点值单独判断
return 1;
}
if (elem >= L.elem[L.length - 1]){//端点值单独判断
return L.length + 1;
}
for (int i = 0; i < L.length - 1; i++){
if (elem > L.elem[i] && elem <= L.elem[i + 1]){
return i + 2;
}
else continue;
}
return 0;
}
/************************************* UnionList ***********************************
//算法函数1:合并线性表La和Lb(相同元素不重复)
//将Lb中与La不同的元素插入到La中去
//时间复杂度:O(La.length * Lb.length), ExistenceElem执行时间和表长成正比,ListInsert和表长无关
*/
void UnionList(Sqlist &La, Sqlist Lb){
for (int i = 0; i < 8; i++){
if (!ExistenceElem(La, Lb.elem[i])){//只需在最开始的La里面查找(Lb中数据插入La中为“追加”),不会影响Lb中重复的元素
ListInsert(La, La.length + 1, Lb.elem[i]);//将Lb中元素追加到La后面,每次La.length都会更新
}
}
}
/************************************ ListMergeOrder *********************************
//算法函数2:合并线性表La和Lb(相同元素重复),并且重新排序
//注意:Lc可以为空,无需初始化第一个元素
//时间复杂度:O(La.length + Lb.length)
*/
void ListMergeOrder(Sqlist &Lc, Sqlist La, Sqlist Lb){
int remark;
for (int i = 0; i < La.length; i++){
Lc.elem[i] = La.elem[i];
++Lc.length;
}
for (int i = 0; i < Lb.length; i++){
remark = ElemLocate(Lc, Lb.elem[i]);
ListInsert(Lc, remark, Lb.elem[i]);
}
}
/***************************** ListMergeOrder_better *******************************************
//算法函数2(效率更高):合并线性表La和Lb(相同元素重复),并且重新排序
//注意要对Lc分配空间,否则不能保证数据是否放得下
//因为这里是对有序线性表合并,所以要比之前的 ListUnion 时间复杂度更低
//时间复杂度:O(La.length + Lb.length)
*/
void ListMergeOrder_better(Sqlist &Lc, Sqlist La, Sqlist Lb){
int i=0,j=0, Len_a, Len_b;
int* pa = La.elem;
int* pb = Lb.elem;
int* pa_last = La.elem + La.length - 1;
int* pb_last = Lb.elem + Lb.length - 1;
Lc.length = La.length + Lb.length;
int* pc =Lc.elem= (int*)malloc(Lc.length*sizeof(int));//保证Lc空间足够
if (!pc){
cout << "ListMergeOrder_better:Memory allocation fail!" << endl;
exit(1);
}
while (pa <= pa_last&&pb <= pb_last){//使用末尾元素指针作为次数判断更加方便
if (*pa <= *pb){//如果将*pa==*pb分开,并且两个元素中只插入一个,就变成了ListUnion函数了
//只是这里时间复杂度更低,因为使用复制代替了元素查找
*pc++ = *pa++;
}
else{
*pc++ = *pb++;
}
}
while (pa <= pa_last){
*pc++ = *pa++;
}
while (pb <= pb_last){
*pc++ = *pb++;
}
}