1.线性表创建、元素插入、元素删除、线性表合并(原创)

参考书籍:数据结构(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<iostream>
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++;
	}
}


  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值