[Algorithms][C]Singly linked list

  1. 插入:头插入,尾插入,及指定位置插入
  2. 删除:头删除,尾删除,及指定位置插入
  3. 逆序:
  4. 查找:
  5. 计数:
  6. 打印:
#include <stdio.h>
#include <Windows.h>


//节点结构体
#define MAX_LEN_IN_KEY 16
typedef struct Node {
	char key[MAX_LEN_IN_KEY+1];
	int value;
	struct Node* next;   
};

typedef Node* PNode;


void domemcpy(char *dest, char *src){
	int count = (MAX_LEN_IN_KEY < strlen(src)) ? MAX_LEN_IN_KEY : strlen(src);
	memset((void*)dest,0,count+1);
	strncpy(dest,src,count);
}

//1.构建一个结点
PNode buildNode(char* key,int value){
	printf("%s\n",__func__);

	PNode node = (PNode)malloc(sizeof(Node));
	if (node == NULL){
		return NULL;
	}

	domemcpy(node->key,key);
	node->value = value;
	node->next = NULL;

	return node;
}

//2.初始化头结点
PNode initLinklist(char* key, int value) {

	return buildNode(key,value);
}

//3.尾插 
PNode insertNodeIntoBack(PNode *pHead, char* key, int value){
	printf("%s\n", __func__);

	PNode newNode = buildNode(key,value);
	if (newNode == NULL) {
		return NULL;
	}

	//(1)链表为空时,直接让phead指向新节点即可
	if (NULL == (*pHead)){
		printf("linklist is empty,set it as head\n");
		*pHead = newNode;
		return newNode;
	}

	//(2)链表不空时,遍历一遍链表,找到最后一个节点,连接在最后一个节点的的后面
	PNode pCur = *pHead;
	while (pCur->next != NULL){
		pCur = pCur->next;
	}
	pCur->next = newNode;

	return newNode;
}

//4.尾删
void deleteNodeFromBack(PNode *pHead)
{
	printf("%s\n", __func__);
	
	if (NULL == (*pHead)){ //(1)链表为空时,直接返回
		printf("linklist is empty,no need to delete\n");
		return;
	}else if (NULL == (*pHead)->next) { //(2)链表中只有一个结点时,free这个节点,并将phead置空
		printf("linklist has only one node\n");
		free(*pHead);
		*pHead = NULL;
	}else{
		printf("linklist has more than one node\n");
		PNode pCur = *pHead;//指向当前节点
		PNode pPrev = pCur;  //指向前一个节点
		//(3)链表中有多个节点时,遍历一遍链表,找到最后一个节点(pCur->next == NULL),并且保存最后一个节点的前一个节点的信息 
		while (pCur->next != NULL){
			pPrev = pCur;
			pCur = pCur->next;
		}
		free(pCur);
		pPrev->next = NULL;
	}
}

//5.头插 
PNode insertNodeIntoFront(PNode *pHead, char* key, int value){
	printf("%s\n", __func__);

	PNode newNode = buildNode(key,value);
	if (newNode == NULL) {
		return NULL;
	}

	//(1) 链表为空时:直接让头结点指向新的节点即可
	if (NULL == (*pHead)){
		printf("linklist is empty,set it as head\n");
		*pHead = newNode;
	}else{
	    //(2)当链表有一个节点或者多个节点时,连接在头节点的的前面,并修改新节点作为头节点
	    newNode->next = *pHead;
		*pHead = newNode;
	}

	return newNode;
}

//6.头删
void deleteNodeFromFront(PNode *pHead){
	printf("%s\n", __func__);

	//链表为空时:直接返回,不需要删除
	if (NULL == (*pHead)) {  
		printf("linklist is empty,no need to delete\n");
		return;
	}

	//链表不为空时:有一个节点和有多个节点可以使用相同的逻辑:旧头节点的下一个节点作为新节点,并将旧头结点置空
	PNode pDel = *pHead;
	*pHead = (*pHead)->next;
	free(pDel);
}

//7.pos位置上插入一个节点
PNode insertNodeAtPos(PNode *pHead,PNode pos, char* key, int value){
	printf("%s\n", __func__);

	if (*pHead == NULL || pos == NULL) { //(1)链表为空时,直接返回 //(2)pos位置是否为空
		return NULL;
	}

	PNode newNode = NULL;
	bool bFind = false;
	PNode pCur = *pHead;//指向当前节点
	while (pCur != NULL) {
		if (pCur == pos) {  //(3)Pos节点是否存在
			bFind = true;
			break;
		}
		pCur = pCur->next;
	}

	if (bFind) {
		newNode = buildNode(key, value);
		if (newNode) {
			//插入一个节点(由于是单链表,所以只能插在pos位置的后面)
			newNode->next = pos->next;
			pos->next = newNode;
		}
	}
	else {
		printf("Pos node is not found to insert\n");
	}

	return newNode;
}

//8.pos位置上删除一个节点
void deleteNodeAtPos(PNode* pHead, PNode pos){
	printf("%s\n", __func__);

	if (*pHead == NULL || pos == NULL) {  //(1)链表为空时,直接返回 ;pos位置是否为空
		return;
	}

	//(2)pos不为空且pos为头结点时,这时就可以转化为删除第一个节点,操作步骤同上面的头删
	if ((*pHead) == pos){
		*pHead = pos->next; //*pHead = (*pHead)->next;
		free(pos);
	}else{ //(3)当pos不是第一个节点时
		PNode pCur = *pHead;//指向当前节点
		PNode pPrev = pCur;  //指向前一个节点
		bool bFind = false;

		while (pCur->next != NULL) {
			if (pCur == pos) {  //Pos节点是否存在
				bFind = true;
				break;
			}
			pPrev = pCur;
			pCur = pCur->next;
		}

		if (bFind) {
			pPrev->next = pos->next;
			free(pos);
		}
		else {
			printf("Pos node is not found to delet\n");
		}
	}
}

//9.逆序
PNode reverseListlink(PNode* pHead) {
	printf("%s\n", __func__);

	if (*pHead == NULL) {  //(1)链表为空,直接返回
		return *pHead;
	}else if ((*pHead)->next == NULL) {  //(2)链表只有一个节点,不需要逆序
		return *pHead;
	}else {                              //(3)链表多个一个节点
		PNode pPre = *pHead;
		PNode pCur = pPre->next;
		
		(*pHead)->next = NULL;  //(旧)头结点next为NULL

		while (pCur != NULL)
		{
			PNode pTmp = NULL;
			pTmp = pCur;       //保存(旧)当前节点
			pCur = pCur->next; //(新)当前节点后移一节点
			pTmp->next = pPre; //(旧)当前节点指向前节点
			pPre = pTmp;       //前节点后移一节点
		}
		*pHead = pPre;         //(新)头节点
		return *pHead;
	}

}

//10.查找key对应的节点
PNode findNode(PNode pHead, char* key)
{
	printf("%s\n", __func__);

	PNode pCur = pHead;
	while (pCur)
	{   
		int lenExpect = strlen(key);
		int lenMeasured = strlen(pCur->key);
		if (lenExpect == lenMeasured && strncmp(pCur->key,key, lenExpect) == 0) //如果存在,返回所在位置
		{
			return pCur;
		}
		pCur = pCur->next;
	}

	printf("can not find the node of key\n");
	return NULL; //不存在,返回NULL
}

//11.打印单链表
void printList(PNode pHead){
	PNode pCur = pHead;
	while (pCur){
		printf("key:%s,value:%d\n", pCur->key,pCur->value);
		pCur = pCur->next;
	}
}

//11.得到单链表中节点的个数
int sizeList(PNode pHead){
	size_t count = 0;

	PNode pCur = pHead;
	while (pCur)
	{
		pCur = pCur->next;
		count++;
	}
	return count;
}



int main()
{
	char key[] = "201901";
	int value = 1;

	PNode pHead = NULL;
#if 1
	pHead = initLinklist(key, value);;
#endif

#if 1
	char key2[] = "201902";
	int value2 = 2;
	insertNodeIntoBack(&pHead, key2, value2);
#endif

#if 1
	char key3[] = "201903";
	int value3 = 4;
	insertNodeIntoFront(&pHead, key3, value3);
#endif

#if 0
	deleteNodeFromBack(&pHead);
#endif 

#if 0
	deleteNodeFromFront(&pHead);
#endif

	PNode pPos = NULL;
#if 1
	pPos = findNode(pHead, key);
#endif

#if 1
	char key4[] = "201904";
	int value4 = 8;
	insertNodeAtPos(&pHead, pPos, key4, value4);
#endif

#if 0
	deleteNodeAtPos(&pHead,pPos);
#endif

#if 1
	reverseListlink(&pHead);
#endif

	int size = sizeList(pHead);
	printf("linklist size:%d\n",size);

	printList(pHead);
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值