数据结构(C语言)之——单链表

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//定义元素类型
typedef struct {	
	char* name; //元素名
	int value; //元素值
}Elem;

//单链表结构。定义元素结点类型:
typedef struct LNode{
    Elem* data;   //每个结点存放一个元素指针(数据域)
	LNode* next; //指针指向下一个结点(指针域)
}LNode, *LinkList;
/*上述定义方式等价于:
typedef struct LNode LNode; //强调这是一个结点
typedef struct LNode *LinkList; //强调这是一个链表
*/

/****************************************定义元素操作*****************************************/
Elem* createElem(char* name, int value); //指定元素名和元素值创建一个新元素
bool alterElem(Elem* e, char* newName, int newValue); //修改元素的值为新的值
bool copyElem(Elem* eCopy, Elem* e); //将元素e的值复制给eCopy。(eCopy仅为一个指针)
bool isSameElem(Elem* e1, Elem* e2); //判断两个元素的所有属性是否相同(元素名和元素值都相同)
void printElem(LNode* p); //打印元素信息

/****************************************创建、初始化和释放*****************************************/
LinkList createList(); //创建一个空链表并初始化
void releaseList(LinkList list); //释放线性表开辟的内存空间
/*************************************************增*************************************************/
bool headInsertList(LinkList list, Elem* e); //头插。在表头位置插入元素e。插入成功返回true,失败返回false
bool tailInsertList(LinkList list, Elem* e); //尾插。在表尾插入元素e。插入成功返回true,失败返回false
bool insertList(LinkList list, int pos, Elem* e); //指定位置插入元素。在单链表的第pos(1≤pos≤n)个位置插入元素e,成功返回true,失败返回false。
/*************************************************删*************************************************/
bool headDeleteList(LinkList list); //头删,删除表中的第1个元素。删除成功返回true,失败返回false
bool tailDeleteList(LinkList list); //尾删,删除表尾元素。删除成功返回true,失败返回false
bool deleteList(LinkList list, int pos); //指定位置删除元素。删除单链表list的第pos(1≤pos≤n)个数据元素。删除成功返回true,删除失败返回false。
bool clearList(LinkList list); //清空单链表。清空成功返回true,清空失败返回false。
/*************************************************改*************************************************/
bool alterList(LinkList list, int pos, char* newName, int newValue); //修改表中第pos(1≤pos≤n)个元素的值。修改成功返回true,修改失败返回false。
/*************************************************查*************************************************/
int locateElemPosition(LinkList list, char* name, int value); //根据元素名和元素值来查找元素结点在链表中的位置,如果有,返回位置pos(1≤pos≤n);如果没有,返回-1
LNode* locateElemPointer(LinkList list, char* name, int value); //根据元素名和元素值来查找元素结点指针,并返回;如果找不到,就返回NULL
bool isNotLegalPosition(LinkList list, int pos); //判断插入位置pos(1≤pos≤n)是否非法。非法则返回true,合法则返回false。
bool isEmpty(LinkList list); //判断单链表是否为空
LNode* getPointer(LinkList list, int pos); //返回指向第pos(1≤pos≤n)个元素结点的指针
int listLength(LinkList list); //求单链表的长度
void printList(LinkList list); //打印单链表
/*************************************************其它*************************************************/ /*
LinkList mergeList(LinkList list1, LinkList list2); //合并单链表。将list2加入到list1后面,返回合并后的新表。合并失败返回NULL
LinkList reverseList(LinkList list); //反转单链表元素,返回一个倒序的新表。反转失败返回NULL。
LinkList reversePartList(LinkList list, int startPos, int endPos); //反转部分单链表元素。反转从第startPos到第endPos的元素,包括startPos和endPos位置的元素。反转失败返回NULL。
int sameElemCount(LinkList list1, LinkList list2); //返回两个单链表中相同元素个数
bool alterListFromOther(LinkList list, int pos, LinkList otherList, int otherPos); //将表list的第pos个元素设置设置为与表otherList的第otherPos个元素相同
*/
void main() {
	LinkList list = createList(); //创建一个带头结点的空链表并初始化
	printf("/*************************************************增*************************************************/\n");
	//头插法插入元素
	headInsertList(list, createElem("a", 1));
	printf("头插法插入元素:(a,1),操作后表为:"); printList(list);
	//指定索引处插入元素
	insertList(list, 2, createElem("b", 2));
	printf("在第2个位置插入元素:(b,2),操作后表为:"); printList(list);
	insertList(list, 2, createElem("c", 3));
	printf("在第2个位置插入元素:(c,3),操作后表为:"); printList(list);
	printf("单链表的长度为:%d\n",listLength(list));
	//尾插法插入元素
	tailInsertList(list, createElem("d", 4));
	printf("尾插法插入元素:(d,4),操作后表为:"); printList(list);

	printf("/*************************************************查*************************************************/\n");
	printf("元素(c,3)在顺序表中的位置为:%d\n", locateElemPosition(list, "c", 3));
	printf("顺序表中第2个元素为:"); printElem(getPointer(list, 2)); printf("\n");
	printf("/*************************************************改*************************************************/\n");
	alterList(list, 4, "x", 100);
	printf("修改顺序表中第4个元素的值为(x, 100),操作后表为:"); printList(list); 
	
	printf("/*************************************************删*************************************************/\n");
	//头删法删除元素
	headDeleteList(list);
	printf("头删法删除元素,操作后表为:");printList(list);
	//指定索引处删除元素
	deleteList(list, 2);
	printf("删除第2个元素,操作后表为:");printList(list);
	//尾删法删除元素
	tailDeleteList(list);
	printf("尾删法删除元素,操作后表为:");printList(list);
	//清空顺序表
	clearList(list);
	printf("清空顺序表,操作后表为:");printList(list);
	printf("顺序表的长度为:%d\n",listLength(list));

	releaseList(list);
}

//指定元素名和元素值创建一个新元素
Elem* createElem(char* name, int value) { 
	Elem* e = (Elem*) malloc(sizeof(Elem));
	if(e == NULL) { //开辟失败则直接返回
		printf("创建元素失败!\n");
		return NULL;
	}
	e->name = (char*) malloc(sizeof(char)*(strlen(name)+1));
	strcpy(e->name, name);
	e->value = value;
	return e;
}

//修改元素的值为新的值。修改成功返回true,修改失败返回false。
bool alterElem(Elem* e, char* newName, int newValue) {
	if(e == NULL || newName == NULL) {
			return false;
	}
	free(e->name);
	e->name = (char* ) malloc(sizeof(char)*(strlen(newName)+1));
	strcpy(e->name, newName);
	e->value = newValue;
	return true;
}

//将元素e的值复制给eCopy。(eCopy仅为一个指针)
bool copyElem(Elem* eCopy, Elem* e) {
	eCopy->name = (char*) malloc(sizeof(char)*(strlen(e->name)+1)); //注意加1,因为有'\0'
	if(eCopy->name == NULL) {
		return NULL;
	}
	strcpy(eCopy->name, e->name); //复制元素名
	eCopy->value = e->value; //复制元素值
	return true;
}

//判断两个元素属性是否相同(元素名和元素值都相同)
bool isSameElem(Elem* e1, Elem* e2) {
	//如果有一个是NULL,返回false
	if(e1 == NULL || e2 == NULL) {
		return false;
	}
	return strcmp(e1->name, e2->name) == 0 ?  e1->value == e2->value : false;
}

//打印元素信息
void printElem(LNode* p) {
	printf("(%s, %d)", p->data->name, p->data->value);
}

/****************************************创建、初始化和释放*****************************************/
//创建一个空链表并初始化
LinkList createList() {
	LinkList list = (LinkList) malloc(sizeof(LNode)); //定义头结点
	list->data = NULL; //数据域为NULL,表示不存放数据
	list->next = NULL;
	return list;
}

//释放线性表开辟的内存空间
void releaseList(LinkList list) {
	LNode* p = list;
	while(list != NULL) {
		p = list; //定位要释放的结点
		list = list->next;

		//释放内存,注意根据条件释放多个位置的内存
		if(p->data != NULL) {
			if(p->data->name != NULL) {
				free(p->data->name); //释放元素名指针
			}
			free(p->data); //释放元素指针
		}
		free(p); //释放结点指针
	}
}

/*************************************************查*************************************************/
//求单链表的长度
int listLength(LinkList list) {
	LNode* p = list;
	int length = 0;
	while(p->next != NULL) {
		length += 1; //这个结点的位置为i
		p = p->next; //往后找一个结点
	}
	return length;
}

//判断插入位置pos(1≤pos≤n)是否非法。非法则返回true,合法则返回false。?
bool isNotLegalPosition(LinkList list, int pos) {
	if(pos < 1 || pos > listLength(list) + 1) {
		return true;
	}
	return false;
}

//判断单链表是否为空
bool isEmpty(LinkList list) {
	if(list == NULL || list->next == NULL) {
		return true;
	}
	return false;
}

//返回指向第pos个元素结点的指针
LNode* getPointer(LinkList list, int pos) {
	if(isNotLegalPosition(list, pos)) {
		return NULL;
	}
	LNode* p = list;
	//找到第pos个结点p,并返回指针
	for(int i = 0; i < pos; i++) {
		p = p->next;
	}
	return p;
}

//打印单链表
void printList(LinkList list) {
	LNode* p = list;
	while(p ->next != NULL) {
		p = p->next; //定位结点
		printf("(%s , %d) ", p->data->name, p->data->value);
	}
	printf("\n");
}

//根据元素名和元素值来查找数据元素e在表中的位置,如果有,返回位置pos(1≤pos≤n);如果没有,返回-1
int locateElemPosition(LinkList list, char* name, int value) {
	if(list == NULL || name == NULL) {
		return -1;
	}
	LNode* p = list;
	int count = 0;
	bool flag = false; //标识是否找到
	while(p->next != NULL) {
		p = p->next;
		count += 1;
		if(strcmp(p->data->name, name) == 0 && p->data->value == value) {
			flag = true;
			break;
		}
	}
	return flag ? count : -1;
}

//根据元素名和元素值来查找元素结点指针,并返回;如果找不到,就返回NULL
LNode* locateElemPointer(LinkList list, char* name, int value) {
	int pos = locateElemPosition(list, name, value);
	return pos == -1 ? NULL : getPointer(list, pos);
}

/*************************************************增*************************************************/
//头插。在表头位置插入元素e。插入成功返回true,失败返回false
bool headInsertList(LinkList list, Elem* e) {
	LNode* node = (LNode*) malloc(sizeof(LNode));
	if(node == NULL || e == NULL) {
		return false; //申请内存失败或元素不存在返回false
	}
	//给结点赋值
	node->data = e;
	//插入链表的头部
	node->next = list->next;
	list->next = node;
	return true;
}

//指定位置插入元素。在单链表的第pos(1≤pos≤n)个位置插入元素e,成功返回true,失败返回false。
bool insertList(LinkList list, int pos, Elem* e) {
	//判断pos是否小于1或者大于链表长度+1
	if(isNotLegalPosition(list, pos)) {
		return false;
	}
	//找到第pos-1个元素结点p
	LNode* p = getPointer(list, pos - 1);
	//创建新结点并赋值
	LNode* newNode = (LNode*) malloc(sizeof(LNode));
	newNode->data = e;
	//将新结点插入到单链表中
	newNode->next = p->next;
	p->next = newNode;
	return true;
}

//尾插。在表尾插入元素e。插入成功返回true,失败返回false
bool tailInsertList(LinkList list, Elem* e) {
	if(list == NULL || e == NULL) {
		return false;
	}
	//返回最后一个元素结点的指针
	LNode* p = getPointer(list, listLength(list));
	//在这个结点后插入新结点
	LNode* newNode = (LNode*) malloc(sizeof(LNode));
	newNode->data = e; //给结点数据域赋值
	newNode->next = p->next;
	p->next = newNode;
	return true;
}

/*************************************************删*************************************************/
//头删,删除表中的第1个元素。删除成功返回true,失败返回false
bool headDeleteList(LinkList list) {
	if(isEmpty(list)) {
		return false;
	}
	LNode* p = list->next;
	list->next = p->next;
	//释放该结点
	free(p->data->name); //释放结点名
	free(p->data); //释放元素
	free(p); //释放结点
	return true;
}

//尾删,删除表尾元素。删除成功返回true,失败返回false
bool tailDeleteList(LinkList list) {
	if(list == NULL) {
		return false;
	}
	LNode* p = getPointer(list, listLength(list) - 1); //获取最后一个结点前面的结点的指针。也可以自己实现。
	LNode* s = p->next;
	p->next = s->next;
	//释放结点s
	free(s->data->name);
	free(s->data);
	free(s);
	return true;
}

//指定位置删除元素。删除单链表list的第pos(1≤pos≤n)个数据元素。删除成功返回true,删除失败返回false。
bool deleteList(LinkList list, int pos) {
	if(list == NULL) {
		return false;
	}
	if(isNotLegalPosition(list, pos)) {
		return false;
	}
	LNode* p = getPointer(list, pos -1); //获取第pos -1 个结点的指针
	LNode* s = p->next; //s为要删除的结点
	p->next = s->next;
	//释放结点s
	free(s->data->name);
	free(s->data);
	free(s);
	return true;
}

//清空单链表。清空成功返回true,清空失败返回false。
bool clearList(LinkList list) {
	if(list == NULL) {
		return false; //list没有头结点
	}
	LNode* p = list->next; //定位要删除的结点
	while(p != NULL) {
		list->next = p->next; //头结点指向p的下一个
		//删除p指向的结点
		free(p->data->name);
		free(p->data);
		free(p);
		//p重新指向list的下一个结点
		p = list->next;
	}
	return true;
}

/*************************************************改*************************************************/
//修改表中第pos(1≤pos≤n)个元素的值。修改成功返回true,修改失败返回false。
bool alterList(LinkList list, int pos, char* newName, int newValue) {
	if(list == NULL || newName == NULL) {
		return false;
	}
	if(isNotLegalPosition(list, pos)) {
		return false;
	}
	LNode* p = getPointer(list, pos);
	alterElem(p->data, newName, newValue);
	return true;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值