严蔚敏数据结构 线性表的实现代码(C语言)可直接运行

这是我在大二学习数据结构中的代码实践,将《数据结构》(严蔚敏)中的伪代码用C语言实现。

本人水平有限,难免存在一些错误,欢迎各位同学批评指正。如果这篇文章对您有所帮助,请留下一个赞吧,谢谢!


目录

顺序实现(动态数组)

 

链式实现(单向链表)


顺序实现(动态数组)

代码如下:

/* 线性表的顺序实现 */
/* Note
  	(1) 优点
        a.节省存储空间;
        b.对线性表中第i个结点的操作易于实现;
        c.容易查找一个结点的前驱和后继。
	(2)缺点
        a.插入和删除操作需要移动数据;
        b.建立空表时,较难确定所需的存储空间。
*/

#include<stdio.h>
#include<stdlib.h>
#define LIST_INIT_SIZE 100 	// 线性表存储空间的初始分配量
#define LISTINCERMENT 10	// 线性表存储空间的分配增量
#define ElemType int
#define ERROR 0

typedef struct
{
	ElemType* elem; 	//  存储空间基址
	int length; 		// 当前长度
	int listsize;		// 当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;

void InitList_Sq(SqList* L)
{
	L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	if(!L->elem) exit(ERROR);
	L->length = 0;
	L->listsize = LIST_INIT_SIZE;
	return;
}


void DestroyList_Sq(SqList* L)
{
	free(L->elem);
	return;
}

void GetElem_Sq(SqList L, int i, ElemType* e)
{
	// SqList中第i个位置的元素是elem[i-1]
	*e = L.elem[i-1];
	return;
}

void ListInsert_Sq(SqList* L, int i, ElemType e)
{
	// 先判断插入位置是否正确
	if(i > L->length+1 || i < 1)  exit(ERROR);
	
	// 再判断是否表满
	if(L->length == L->listsize)
	{
		// 如果表满,则新分配一个更大的内存
		ElemType* newbase = (ElemType *)realloc( L->elem, (L->listsize + LISTINCERMENT)*sizeof(ElemType));
		if(!newbase) exit(ERROR);
		
		// 基地址指向新的内存		
		L->elem = newbase;
		
		// 新的顺序表内存大小
		L->listsize += LISTINCERMENT;
	}
	
	// 从最后一个元素的下一个位置开始,将插入位置及之后的元素向后滑动一位
	for(int j = L->length; j >= i; j--)
	{
		L->elem[j] = L->elem[j-1];
	}
	
	// 此时第i个位置空出,插入元素e
	L->elem[i-1] = e;
	++ L->length;
	return;
}

void ListDelete_Sq(SqList* L, int i, ElemType* e)
{
	// 先判断顺序表是否为空
	if(L->length == 0) exit(ERROR);
	
	// 再判断删除位置是否正确
	if(i < 1 || i > L->length) exit(ERROR);
	
	// 将待删除位置的元素取出
	*e = L->elem[i-1];
	for(i; i<L->length ; ++i)
	{
		L->elem[i-1] = L->elem[i];
	}
	--L->length;
	return;
}

void ListTraverse_Sq(SqList L)
{
	for(int i=0; i<L.length; ++i)
	{
		printf("%d ",L.elem[i]);
	}
	return;
}

void menu()
{
	printf("-------------------------------------\n");
	printf("1、初始化顺序表        2、销毁顺序表\n");
	printf("3、插入元素            4、删除元素\n");
	printf("0、退出\n");
	printf("-------------------------------------\n");
}


int main()
{
	SqList L;
	while(true)
	{
		menu();
		int choice;
		scanf("%d",&choice);
		switch(choice)
		{
		case 1:
			InitList_Sq(&L);
			break;
		case 2:
			DestroyList_Sq(&L);
			break;
		case 3:
			{
				int i;
				printf("请输入要插入的位置:");
				scanf("%d",&i);
	
				ElemType e;
				printf("请输入要插入的元素:");
				scanf("%d",&e);
	
				ListInsert_Sq(&L, i, e);
				printf("当前顺序表:");
				ListTraverse_Sq(L);
				printf("\n");
				break;
			}
		case 4:
			{
				int i;
				printf("请输入要删除的位置:");
				scanf("%d",&i);
	
				ElemType e;
				ListDelete_Sq(&L, i, &e);
				printf("当前顺序表:");
				ListTraverse_Sq(L);
				printf("\n");
				break;
			}
		case 0:
			{
				DestroyList_Sq(&L);
				return 0;
			}
		}
	}
}

 


链式实现(单向链表)

代码如下:

/* 线性表的链式实现 */
/* Note
  	(1) 优点
        a. 插入和删除不需要移动数据(时间复杂性低);
        b.不需预先分配空间。
    (2)缺点
        a.指针占用存储空间,增加了内存负担。
        b.只能顺序查找(操作)。
*/
#include<stdio.h>
#include<stdlib.h>
#define ERROR 0
#define ElemType int

typedef struct LNode
{
	ElemType data;
	struct LNode* next;
} LNode, * LinkList;


// 初始化一个带头结点的空链表L
LinkList InitList_L()
{
	// 构造一个头结点L
	static LinkList L;
	L = (LNode*)malloc(sizeof(LNode));
	if(!L) exit(ERROR);

	// 让L的数据域存储链表的长度信息
	L->data = 0;
	L->next = NULL;

	return L;
}


// 生成一个含有n个结点的链表
LinkList CreateList_L(int n)
{
	// 建立头结点L
	static LinkList L;
	L = (LNode*)malloc(sizeof(LNode));
	if(!L) exit(ERROR);
	L->data = n;
	L->next = NULL;
	// 尾指针 用于尾插法 
	LinkList rear = L;

	for(int i = 0; i < n; ++i)
	{
		// 建立新的结点p
		LinkList p = (LNode*)malloc(sizeof(LNode));
		if(!p) exit(ERROR);
		scanf("%d",&p->data);

		// 尾插法
		p->next = NULL;
		rear->next = p;
		rear = p; 
	}
	return L;
}


void DestroyList_L(LinkList L)
{
	LinkList p = L;
	while(p)
	{
		p = p->next;
		free(L);
		L = p;
	}
}


void ListInsert_L(LinkList L, int i, ElemType e)
{
	// 在带头结点的单链线性表L中第i个位置之前插入元素e

	// 指针p指向头结点L
	LinkList p = L;

	// 判断插入位置是否正确
	if(i > L->data+1 || i < 1)  exit(ERROR);

	// 寻找第i-1个结点
	for(int j = 0; j < i-1; ++j)
	{
		p = p->next;
	}

	// 插入新结点S
	LinkList S;
	S = (LNode*)malloc(sizeof(LNode));
	if(!S) exit(ERROR);
	S->data = e;
	S->next = p->next;
	p->next = S;

	// 链表长度+1
	++ L->data;

	return;
}


void ListDelete_L(LinkList L, int i, ElemType* e)
{
	// 先判断删除的位置是否正确
	if(i < 1 || i > L->data) exit(ERROR);

	// 指针p指向头结点L
	LinkList p = L;

	// 找到第i-1个结点
	for(int j = 0; j < i-1; ++j)
	{
		p = p->next;
	}

	// 指针q指向第i个元素
	LinkList q = p->next;
	*e = q->data;
	p->next = q->next;
	free(q);

	// 链表长度减1
	-- L->data;
}

void ListTraverse_L(LinkList L)
{
	LinkList p = L->next;
	while(p)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	return;
}


void menu()
{
	printf("----------------------------------------------\n");
	printf("1、初始化带头节点链表  2、创建含n个元素的链表\n");
	printf("3、插入结点            4、删除节点\n");
	printf("0、销毁链表并退出\n");
	printf("----------------------------------------------\n");
}



int main()
{
	static LinkList L;
	while(true)
	{
		menu();
		int choice;
		scanf("%d",&choice);
		switch(choice)
		{
			case 1:
				{
					L = InitList_L();
					break;
				}
			case 2:
				{
					int n;
					printf("请输入链表长度:");
					scanf("%d",&n);

					printf("请输入n个节点的数据(用空格分开):");
					L = CreateList_L(n);
					ListTraverse_L(L);
					printf("\n");
					break;
				}
			case 3:
				{
					int i;
					printf("请输入要插入的位置:");
					scanf("%d",&i);

					ElemType e;
					printf("请输入要插入的元素:");
					scanf("%d",&e);

					ListInsert_L(L, i, e);
					ListTraverse_L(L);
					printf("\n");
					break;
				}
			case 4:
				{
					int i;
					printf("请输入要删除的位置:");
					scanf("%d",&i);

					ElemType e;

					ListDelete_L(L, i, &e);
					ListTraverse_L(L);
					printf("\n");
					break;
				}
			case 0:
				{
					DestroyList_L(L);				
					return 0;
				}
		}
	}
}

 

  • 17
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值