C语言线性表

/* 宏定义 */
#define LIST_INIT_SIZE 100				//顺序表存储空间的初始分配量 
#define LISTINCREMENT  10				//顺序表存储空间的分配增量

/* 顺序表类型定义 */
#ifndef LELEMTYPE_SQ
#define LELEMTYPE_SQ
typedef int LElemType_Sq;
#endif

typedef struct
{
	LElemType_Sq *elem;					//存储空间基址(指向第一个结点的指针) 
	int length;							//当前顺序表长度 
	int listsize;						//当前分配的存储容量 
}SqList;								//顺序表0号单元正常使用 

线性表基本操作

Status InitList_Sq(SqList *L)
{
	(*L).elem = (LElemType_Sq*)malloc(LIST_INIT_SIZE*sizeof(LElemType_Sq));
	if(!(*L).elem)
		exit(OVERFLOW); 				//分配内存失败

	(*L).length = 0;					//初始化顺序表长度为0
	(*L).listsize = LIST_INIT_SIZE;		//顺序表初始内存分配量

	return OK;							//初始化成功	 
} 

void ClearList_Sq(SqList *L)
{
	(*L).length = 0;
}

void DestroyList_Sq(SqList *L)
{
	free((*L).elem);

	(*L).elem = NULL;					//释放内存后置空指针 
	(*L).length = 0;
	(*L).listsize = 0;
}

Status ListEmpty_Sq(SqList L)
{
	return 	L.length==0 ? TRUE : FALSE;
}

int ListLength_Sq(SqList L)
{
	return L.length;	
}

Status GetElem_Sq(SqList L, int i, LElemType_Sq *e)
{ 
	if(i<1 || i>L.length)
		return ERROR;					//i值不合法
	else
		*e = L.elem[i-1];

	return OK;
}

/*════╗
║算法2.6 ║ 
╚════*/
int LocateElem_Sq(SqList L, LElemType_Sq e, Status(Compare)(LElemType_Sq, LElemType_Sq))
{
	int i = 1;							//i的初值为第一个元素的位序
	
	while(i<=L.length && !Compare(e, L.elem[i-1]))
		++i;

	if(i<=L.length)
		return i;
	else
		return 0; 
}

Status PriorElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *pre_e)
{
	int i = 1;
	
	if(L.elem[0]!=cur_e)				//第一个结点无前驱 
	{
		while(i<L.length && L.elem[i]!=cur_e)
			++i;
		
		if(i<L.length)
		{
			*pre_e = L.elem[i-1];
			return OK;
		}	
	}
			
	return ERROR;
}

Status NextElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *next_e)
{
	int i = 0;
	
	while(i<L.length && L.elem[i]!=cur_e)
		++i;

	if(i<L.length-1)					//最后一个结点无后继 
	{
		*next_e = L.elem[i+1];	
		return OK;
	}

	return ERROR;
}

/*════╗
║算法2.4 ║ 
╚════*/
Status ListInsert_Sq(SqList *L, int i, LElemType_Sq e)
{
	LElemType_Sq *newbase; 
	LElemType_Sq *p, *q;

	if(i<1 || i>(*L).length+1)
		return ERROR;					//i值不合法

	if((*L).length >= (*L).listsize)	//若存储空间已满,需开辟新空间 
	{
		newbase = (LElemType_Sq*)realloc((*L).elem, ((*L).listsize+LISTINCREMENT)*sizeof(LElemType_Sq));
		if(!newbase)
			exit(OVERFLOW);

		(*L).elem = newbase;
		(*L).listsize += LISTINCREMENT;
	}
	
	q = &(*L).elem[i-1];				//q为插入位置 
	
	for(p=&(*L).elem[(*L).length-1]; p>=q; --p)
		*(p+1) = *p;					//插入位置及之后的元素右移 
	
	*q = e;								//插入e 
	(*L).length++;						//表长增1

	return OK; 
}

/*════╗
║算法2.5 ║ 
╚════*/
Status ListDelete_Sq(SqList *L, int i, LElemType_Sq *e)
{
	LElemType_Sq *p, *q;
		
	if(i<1 || i>(*L).length)
		return ERROR;					//i值不合法
	
	p = &(*L).elem[i-1];				//p为被删除元素的位置 
	*e = *p;
	q = (*L).elem+(*L).length-1; 		//表尾元素位置 
	
	for(++p; p<=q; ++p)
		*(p-1) = *p;					//被删元素之后的元素左移 

	(*L).length--;						//表长减1

	return OK;
}

Status ListTraverse_Sq(SqList L, void(Visit)(LElemType_Sq))
{
	int i;

	for(i=0; i<L.length; i++)
		Visit(L.elem[i]);
	
	return OK;
}
/* 测试调用的函数原型 */
Status CmpGreater(LElemType_Sq e, LElemType_Sq data);
	//若data>e,返回TRUE,否则返回FALSE
	
void PrintElem(LElemType_Sq e);
	//测试函数,打印整型 

int main(int argc, char **argv)
{
	SqList L;
	int i;
	LElemType_Sq e;

	printf("▼1\n▲函数 InitList_Sq 测试...\n");		//1.函数InitList_Sq测试
	{
		printf("初始化顺序表 L ...\n");					 
		InitList_Sq(&L);
		printf("\n");	
	}
	PressEnter;
	
	printf("▼4\n▲函数 ListEmpty_Sq 测试...\n");		//4.函数ListEmpty_Sq测试
	{
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");
		printf("\n");	
	}
	PressEnter;
		
	printf("▼10\n▲函数 ListInsert_Sq 测试...\n");		//10.函数ListInsert_Sq测试
	{
		for(i=1; i<=6; i++)									
		{
			printf("作为示范,在 L 第 %d 个位置插入 \"%d\"...\n", i, 2*i);
			ListInsert_Sq(&L, i, 2*i);
		}
		printf("\n");	
	}
	PressEnter;
			
	printf("▼12\n▲函数 ListTraverse_Sq 测试...\n");	//12.函数ListTraverse_Sq测试
	{
		printf(" L 中的元素为:L = ");						 
		ListTraverse_Sq(L, PrintElem);
		printf("\n\n");	
	}
	PressEnter;
		
	printf("▼5\n▲函数 ListLength_Sq 测试...\n");		//5.函数ListLength_Sq测试
	{
		i = ListLength_Sq(L);
		printf(" L 的长度为 %d \n", i);
		printf("\n");	
	}
	PressEnter;
			
	printf("▼11\n▲函数 ListDelete_Sq 测试...\n");		//11.函数ListDelete_Sq测试
	{
		ListDelete_Sq(&L, 6, &e);
		printf("删除 L 中第 6 个元素 \"%d\" ...\n", e);
		printf(" L 中的元素为:L = ");						 
		ListTraverse_Sq(L, PrintElem);
		printf("\n\n");
	}
	PressEnter;
		
	printf("▼6\n▲函数 GetElem_Sq 测试...\n");			//6.函数GetElem_Sq测试
	{
		GetElem_Sq(L, 4, &e);
		printf(" L 中第 4 个位置的元素为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
		
	printf("▼7\n▲函数 LocateElem_Sq 测试...\n");	  	//7.函数LocateElem_Sq测试
	{
		i = LocateElem_Sq(L, 7, CmpGreater);
		printf(" L 中第一个元素值大于 \"7\" 的元素的位置为 %d \n", i); 
		printf("\n");
	}
	PressEnter;
		
	printf("▼8\n▲函数 PriorElem_Sq 测试...\n");		//8.函数PriorElem_Sq测试
	{
		PriorElem_Sq(L, 6, &e);
		printf("元素 \"6\" 的前驱为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
	printf("▼9\n▲函数 NextElem_Sq 测试...\n");		//9.函数NextElem_Sq测试
	{
		NextElem_Sq(L, 6, &e);
		printf("元素 \"6\" 的后继为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
	printf("▼2\n▲函数 ClearList_Sq 测试...\n");		//2.函数ClearList_Sq测试
	{
		printf("清空 L 前:");
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");		
		ClearList_Sq(&L);
		printf("清空 L 后:");
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");
		printf("\n");
	}
	PressEnter;
		
	printf("▼3\n▲函数 DestroyList_Sq 测试...\n");		//3.函数DestroyList_Sq测试
	{
		printf("销毁 L 前:");
		L.elem ? printf(" L 存在!\n") : printf(" L 不存在!!\n");
		DestroyList_Sq(&L);
		printf("销毁 L 后:");
		L.elem ? printf(" L 存在!\n") : printf(" L 不存在!!\n");
		printf("\n");
	}
	PressEnter;
		
	return 0;
}

Status CmpGreater(LElemType_Sq e, LElemType_Sq data)
{
	return data>e ? TRUE : FALSE;
}

void PrintElem(LElemType_Sq e)
{
	printf("%d ", e);
}

线性表并集∪

/*════╗
║ 算法2.1║ 
╚════*/
void Union(SqList *La, SqList Lb)
{
	int La_len, Lb_len;
	int i;
	LElemType_Sq e;
	
	La_len = ListLength_Sq(*La);			//求顺序表长度 
	Lb_len = ListLength_Sq(Lb);
	
	for(i=1; i<=Lb_len; i++)
	{
		GetElem_Sq(Lb, i, &e);				//取Lb中第i个元素赋给e 
		if(!LocateElem_Sq(*La, e, equal)) 	//若e不在La中则插入
			ListInsert_Sq(La, ++La_len, e);	
	}
}

Status equal(LElemType_Sq e1, LElemType_Sq e2)
{
   return e1==e2 ? TRUE : FALSE;
}
void PrintElem(LElemType_Sq e);		//测试函数,打印整型 
	
int main(int argc, char **argv)
{
	SqList La, Lb;
	LElemType_Sq a[5] = {5, 2, 1, 3, 9};
	LElemType_Sq b[7] = {7, 2, 6, 9, 11, 3, 10};
	int i;
	
	InitList_Sq(&La);					//初始化La 
	for(i=1; i<=5; i++)
		ListInsert_Sq(&La, i, a[i-1]);	
	InitList_Sq(&Lb);					//初始化Lb 
	for(i=1; i<=7; i++)
		ListInsert_Sq(&Lb, i, b[i-1]);

	printf("La = ");					//输出La 
	ListTraverse_Sq(La, PrintElem); 
	printf("\n");
	printf("Lb = ");					//输出Lb 
	ListTraverse_Sq(Lb, PrintElem); 
	printf("\n\n");
	
	printf("La = La∪Lb = ");			//输出新表La的内容
	Union(&La, Lb);
	ListTraverse_Sq(La, PrintElem);
	printf("\n\n");
	
	return 0;
}

void PrintElem(LElemType_Sq e)
{
	printf("%d ", e);
}

线性表合并

/*━━━━━━━━━━━━━━━━━━━━━┓
┃算法2.2:求C=A+B,A,B,C均为非递减序列 ┃
┗━━━━━━━━━━━━━━━━━━━━━*/
void MergeSqList_1(SqList La, SqList Lb, SqList *Lc)	//调用顺序表函数进行合并 
{
	int La_len, Lb_len; 
	int i, j, k;
	LElemType_Sq ai, bj;
	
	i = j = 1;
	k = 0;
	
	InitList_Sq(Lc);					//初始化Lc	
	La_len = ListLength_Sq(La);			//获取La、Lb长度 
	Lb_len = ListLength_Sq(Lb);	 

	while(i<=La_len && j<=Lb_len)		//La及Lb均未扫描完 
	{
		GetElem_Sq(La, i, &ai);
     	GetElem_Sq(Lb, j, &bj);
     	
     	if(ai<=bj)
     	{
     		ListInsert_Sq(Lc, ++k, ai);
     		i++;
     	}
     	else
     	{
			ListInsert_Sq(Lc, ++k, bj);
			j++;
		}
	} 
	
	while(i<=La_len)					//表La还未扫描完 
	{
		GetElem_Sq(La, i++, &ai);
		ListInsert_Sq(Lc, ++k, ai);
	}
   
	while(j<=Lb_len)					//表Lb还未扫描完
	{
		GetElem_Sq(Lb, j++, &bj);
		ListInsert_Sq(Lc, ++k, bj);
	}
}

/*━━━━━━━━━━━━━━━━━━━━━┓
┃算法2.7:求C=A+B,A,B,C均为非递减序列 ┃
┗━━━━━━━━━━━━━━━━━━━━━*/
void MergeSqList_2(SqList La, SqList Lb, SqList *Lc)
{
	LElemType_Sq *pa, *pb, *pc;
	LElemType_Sq *pa_last, *pb_last;
		
	pa = La.elem;						//指向La第一个元素 
	pb = Lb.elem;						//指向Lb第一个元素
	
										//不用InitList_Sq创建Lc 
	(*Lc).listsize = (*Lc).length = La.length + Lb.length;
	pc = (*Lc).elem = (LElemType_Sq *)malloc((*Lc).listsize*sizeof(LElemType_Sq));
	if(!pc) 
		exit(OVERFLOW);
	
	pa_last = La.elem + La.length - 1;	//指向La最后一个元素
	pb_last = Lb.elem + Lb.length - 1;	//指向Lb最后一个元素
	
	while(pa<=pa_last && pb<=pb_last) 	//La和Lb均未扫描完 
	{
		if(*pa <= *pb)
			*pc++ = *pa++;
		else
			*pc++ = *pb++;
	}
	
	while(pa <= pa_last)				//表La未扫描完 
		*pc++ = *pa++;					//插入La的剩余元素

	while(pb <= pb_last)				//表Lb未扫描完
		*pc++ = *pb++;					//插入Lb的剩余元素
}
void PrintElem(LElemType_Sq e);			//测试函数,打印整型 
	
int main(int argc, char **argv)
{
	SqList La, Lb, Lc1, Lc2;
	LElemType_Sq a[4] = {3, 5, 8, 11};
	LElemType_Sq b[7] = {2, 6, 8, 9, 11, 15, 20};
	int i;
	
	InitList_Sq(&La);					//初始化La 
	for(i=1; i<=4; i++)
		ListInsert_Sq(&La, i, a[i-1]);	
	InitList_Sq(&Lb);					//初始化Lb 
	for(i=1; i<=7; i++)
		ListInsert_Sq(&Lb, i, b[i-1]);

	printf("La = ");					//输出La 
	ListTraverse_Sq(La, PrintElem); 
	printf("\n");
	printf("Lb = ");					//输出Lb 
	ListTraverse_Sq(Lb, PrintElem); 
	printf("\n\n");
	
	MergeSqList_1(La, Lb, &Lc1);		//合并A与B,算法2.6 
	printf("合并La和Lb为Lc1 = "); 		//输出Lc1 
	ListTraverse_Sq(Lc1, PrintElem);
	printf("\n\n");

	MergeSqList_2(La, Lb, &Lc2);		//合并A与B,算法2.7  
	printf("合并La和Lb为Lc2 = "); 		//输出Lc2 
	ListTraverse_Sq(Lc2, PrintElem);
	printf("\n\n");
	
	return 0;
}

void PrintElem(LElemType_Sq e)
{
	printf("%d ", e);
}

### C语言线性表的实现与操作 #### 1. 线性表的概念 线性表是一种基本的数据结构,其特点是数据元素之间具有一对一的关系。在线性表中,除了第一个和最后一个元素外,其他每个元素都有唯一的一个前驱和后继[^2]。 #### 2. 线性表的实现方式 线性表可以通过两种主要的方式实现:顺序表和链表。 ##### (1) **顺序表** 顺序表是通过一段连续的内存空间来存储线性表中的元素。以下是基于数组的顺序表示例: ```c #define MAXSIZE 100 typedef int ElemType; // 定义顺序表结构体 typedef struct { ElemType data[MAXSIZE]; int length; } SeqList; ``` - `data` 数组用于存储线性表中的元素。 - `length` 表示当前线性表的实际长度。 ###### 基本操作函数原型 以下是一些常见的顺序表操作函数声明: ```c void InitSeqList(SeqList *L); // 初始化顺序表 bool InsertSeqList(SeqList *L, int pos, ElemType e); // 插入元素 ElemType DeleteSeqList(SeqList *L, int pos); // 删除指定位置的元素 int LocateSeqList(SeqList L, ElemType e); // 查找元素的位置 void PrintSeqList(SeqList L); // 打印顺序表 ``` ###### 示例代码 初始化并打印顺序表的操作如下所示: ```c #include <stdio.h> #include <stdlib.h> void InitSeqList(SeqList *L) { L->length = 0; // 初始为空表 } bool InsertSeqList(SeqList *L, int pos, ElemType e) { if (pos < 1 || pos > L->length + 1) { // 检查插入位置合法性 printf("Insert position error!\n"); return false; } if (L->length >= MAXSIZE) { // 检查容量是否已满 printf("Table is full!\n"); return false; } for (int i = L->length; i >= pos; --i) { // 后移元素 L->data[i] = L->data[i - 1]; } L->data[pos - 1] = e; // 插入新元素 ++(L->length); return true; } void PrintSeqList(SeqList L) { for (int i = 0; i < L.length; ++i) { printf("%d ", L.data[i]); } printf("\n"); } ``` ##### (2) **单链表** 单链表是由一系列节点组成,每个节点包含两个部分:数据域 (`data`) 和指针域 (`next`)。以下是单链表的基本定义: ```c typedef struct Node { ElemType data; struct Node *next; } LinkNode; typedef struct { LinkNode *head; } LinkedList; ``` - `LinkNode` 是链表的节点结构,其中 `data` 存储实际数据,`next` 指向下一个节点。 - `LinkedList` 结构用来管理整个链表,通常只保存头结点地址。 ###### 单链表常见操作 一些常用的单链表操作包括: ```c void CreateLinkedListHead(LinkedList *L); // 头插法创建链表 void CreateLinkedListTail(LinkedList *L); // 尾插法创建链表 bool InsertLinkedList(LinkNode *p, ElemType e); // 在某个节点之后插入新节点 ElemType DeleteLinkedList(LinkNode *p); // 删除某节点后的节点 void PrintLinkedList(LinkNode *head); // 遍历并打印链表 ``` ###### 创建单链表的例子 以下是一个简单的尾插法创建单链表的代码片段: ```c void CreateLinkedListTail(LinkedList *L) { L->head = (LinkNode *)malloc(sizeof(LinkNode)); // 创建头结点 L->head->next = NULL; LinkNode *tail = L->head; // 记录尾部 ElemType value; printf("Enter elements (-1 to end):\n"); while (scanf("%d", &value), value != -1) { LinkNode *newNode = (LinkNode *)malloc(sizeof(LinkNode)); newNode->data = value; newNode->next = NULL; tail->next = newNode; // 新节点接在尾部 tail = newNode; // 更新尾部指针 } } ``` #### 3. 总结 无论是顺序表还是单链表,它们都提供了灵活的方式来管理和操作一组具有线性关系的数据。具体选择哪种实现取决于应用场景的需求。如果需要频繁随机访问,则优先考虑顺序表;而如果更关注动态增删操作效率,则更适合采用单链表[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

取个名字真难啊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值