简单的单链表(2)

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h> 
typedef struct ElementData
{
	int index; 
} Item ; 

typedef struct node 
{
	Item item;
	struct node * nextNode;
} Node;

typedef Node * linkList ;

Node * CreateInsertNode(Item *item) ;


/*链表初始化   */ 
bool initList(linkList *plist)
{
	*plist = (linkList)malloc(sizeof(Node)); 
	if(*plist == NULL)
	{
		return false;
	}
	(*plist)->nextNode = NULL;
	return true;	
}

/*返回链表长度  */
int getListLength(linkList *plist)
{
	int length = 0;
	Node * node = (*plist)->nextNode;
	while(node != NULL)
	{
		length ++;
		node = node->nextNode;	
	}
	return length;
} 

/*返回在链表L中第一个与Item相同的元素的位序, 没有返回为0	*/
//两个结构体不能用 == 直接进行比较 
int locateElem(linkList  L, int item)
{
	int index = 0;
	while(L)
	{
		index ++; 
		if(L->nextNode->item.index == item)
		{
			return index; 
		}
		L = L->nextNode; 
	}	
	return index;
} 

/*返回在链表L的index-1个位置的元素	*/
//ndex-1个位置避免在index个位置插入的时候出错 
Node * getNode(linkList *L, int index)
{
	linkList p = (*L);
	
	int j = 1;
	while(p != NULL && j < index)
	{
		p = p->nextNode;
		j++; 
	}
		
	if(p == NULL || j > index)
	{
		fprintf(stderr, "要找的元素位置超出链表的长度.\n");
		exit(EXIT_FAILURE);
	}	

	return p;	
} 

/*在链表L的index个位置插入item	*/
void listInsert(linkList *L, int index, Item *item)
{	
	//得到index-1的元素 
	linkList currentNode;
	currentNode = getNode(L, index);
	
	//创建要插入的元素 
	linkList insertNode = CreateInsertNode(item) ;
	
	//插入到链表中 
	insertNode->nextNode = currentNode->nextNode;
	currentNode->nextNode = insertNode;		
}

/*把位于链表L的index个位置的元素删掉, 并用item返回其值		*/
void listDelect(linkList *L, int index, Item *item)
{
	//得到index-1的元素 
	linkList currentNode = getNode(L, index);
	
	//删掉元素 
	linkList delectNode = currentNode->nextNode;
	currentNode->nextNode = delectNode->nextNode;
	*item = delectNode->item;
	free(delectNode);
} 

/*头插入	*/
void CreateListHead(linkList *L, Item *item)
{	
	//创建要插入的元素并初始化 
	Node *insertNode = CreateInsertNode(item) ;
	
	//插入 
	linkList head = *L;
	insertNode->nextNode = head->nextNode;
	head->nextNode = insertNode; 		
}


/*尾插入	*/
void CreateListTail(linkList *L, Item *item)
{
	//创建初始化要插入的元素 
	linkList insertNode = CreateInsertNode(item) ;
	
	//找到最后一个元素 
	linkList list = (*L)->nextNode;
	while(list->nextNode != NULL)
	{ 
		list = list->nextNode; 
	} 
	
	//插入 
	list->nextNode = insertNode;
} 


/*删除	*/
void ClearList(linkList *L)
{
	linkList list = (*L)->nextNode ;
	linkList p ;
	while( list != NULL )
	{	
		p = list->nextNode;
		free(list);
		list = p;
	}
	(*L)->nextNode = NULL;
} 

/*输出链表	*/
void listTraverse(linkList *L)
{
	linkList p = (*L)->nextNode;
	while(p)
	{
		printf("%d ,",p->item.index);
		p = p->nextNode;
	}
}

/*创建要插入的元素	返回创建的node指针	*/
Node * CreateInsertNode(Item *item)
{
	Node * insertNode = (linkList)malloc(sizeof(Node));
	if(insertNode == NULL)
	{
		fprintf(stderr,"尾插入错误");
		exit(EXIT_FAILURE);
	} 
	insertNode->item = *item ;
	insertNode->nextNode = NULL;
	return insertNode;
} 

/*单链表翻转/逆序	*/
//current始终保持在第一位,pnext与prev遍历并完成交换。
void ListReverse(linkList *L)
{
	linkList current; //当前节点 
	linkList next;	//下一节点 
	linkList prev;	//上一节点 
	
	current = (*L)->nextNode;
	next = current->nextNode;
	current->nextNode = NULL;
	
	while(next){
		prev = next->nextNode;
		next->nextNode = current;
		current = next;
		next = prev;
	}
	(*L)->nextNode = current;
} 

/*单链表翻转/逆序	*/
//current始终是原链表的第一个数,然后把pnext不断移动到首位。
void ListReverse1(linkList *L)
{
	linkList current; //当前节点 
	linkList next;	//下一节点 
	
	current = (*L)->nextNode;
	
	while(current->nextNode != NULL){
		next = current->nextNode;
		current->nextNode = next->nextNode;
		next->nextNode = (*L)->nextNode;
		(*L)->nextNode = next; 
	}
} 

/*单链表翻转/逆序	*/
//重新建立一个单链表newList,每次将L中的第一个结点放到newList后面
linkList  ListReverse2(linkList *L)
{
	linkList newlist = CreateInsertNode( &((*L)->item) ); 
	if( (*L)->nextNode == NULL)
	{
		return NULL;
	}
	linkList firstNode; 
	while( (*L)->nextNode )
	{
		firstNode = newlist->nextNode;
		newlist->nextNode = (*L)->nextNode;
		(*L)->nextNode = (*L)->nextNode->nextNode;
		newlist->nextNode->nextNode = firstNode;			
	}
	free(*L);
	return newlist;	
}

// 获取单链表倒数第N个结点值
//建立两个指针,第一个先走n步,然后第2个指针也开始走,
//两个指针步伐(前进速度)一致。当第一个结点走到链表末尾时,
//第二个节点的位置就是我们需要的倒数第n个节点的值。 
void GetNthNodeFromBack(linkList *L, int n, Item *item)
{
	linkList list = (*L)->nextNode;
	linkList last = (*L)->nextNode;
	int index = 1;
	
	while(list->nextNode != NULL && index < n)
	{
		index++;
		list = list->nextNode;
	}
	
	if(list->nextNode == NULL || index > n)
	{
		fprintf(stderr, "要找的元素位置超出链表的长度.\n");
		exit(EXIT_FAILURE);
	}
	
	while(list->nextNode != NULL)
	{
		list = list->nextNode;
		last = last->nextNode;	
	}
	*item = last->item;
}

//找到链表的中间节点 
void GetMidNode(linkList *L, Item *e) 
{
	linkList first = *L;
	linkList second = *L; 
	//first移动的速度是second的2倍 
	while(first->nextNode){
		if(first->nextNode->nextNode){
			first = first->nextNode->nextNode;
			second = second->nextNode;
		}else{
			first = first->nextNode;
		}	
	}
	
	*e = second->item;
}

//删除重复的节点
void RemoveDupNode(linkList *L)
{
	linkList first = *L; //用于遍历链表 
	linkList second ;
	linkList delNode ;
	
	while(first->nextNode){		
		second = first->nextNode;  //从first后面开始遍历 
		while(second->nextNode){
			//判断节点是否相等			
			if(second->nextNode->item.index == first->nextNode->item.index){
				//删除节点 
				delNode = second->nextNode;
				second->nextNode = delNode->nextNode;				
				free(delNode);
			}else{
				second = second->nextNode;
			}
		}		
		first = first->nextNode;
	}
} 

//在单链表第n个位置建环
//找到环入口点first,把最后的指针curr指向first 
void BulidListLoop(linkList *L, int num)
{
	linkList first = *L;
	linkList curr ;
	
	if(!first || num < 0){
		fprintf(stderr,"建环失败.");
		exit(EXIT_FAILURE); 
	}
	
	for(int i = 0; i < num; i++){
		if(!first){
			fprintf(stderr,"建环失败,超出链表长度.");
			exit(EXIT_FAILURE); 
		}
		first = first->nextNode;
	}
	
	curr = first;
	
	while(curr->nextNode){
		curr = curr->nextNode;
	}

	curr->nextNode = first;	
}  

//判断链表是否有环
//设两个工作指针,一个快一个慢,如果有环的话,它们会必然在某点相遇。
int hasLoop(linkList *L)
{
	linkList first = *L;
	linkList second = *L;
	
	while(first && second && second->nextNode){
		first = first->nextNode;
		if(second->nextNode){
			second = second->nextNode->nextNode;	
		}
		if(first == second){
			return 1;	
		}
	}
	
	return 0;
} 

//判断链表是否有环
//设两个工作指针p、q,p总是向前走,但q每次都从头开始走,
//对于每个节点,看p走的步数是否和q一样
int hasLoop1(linkList *L)
{
	linkList first = *L;
	int setp = 0;
	
	while(first){
		setp ++;		
		linkList second = *L;
		int index = 0;		
		while(second){
			index ++;
			if(first == second){
				if(setp == index){ //步数相等说明没环 
					break;
				}else{
					return 1; 	
				}	
			}
			second = second->nextNode;
		}
		first = first->nextNode;
	}
	
	return 0;		
}

/*测试	*/
int main(void)
{
	linkList L;
	
	if(!initList(&L))
	{
		fprintf(stderr,"初始化错误");
		exit(EXIT_FAILURE);	
	}
	Item item1 = {
		item1.index = 5 
	};
	
	Item item2 = {
		item2.index = 6
	};
	
	Item item3 = {
		item3.index = 7
	};
	
	Item item4 = {
		item4.index = 6
	};
	
	Item item5 = {
		item5.index = 9
	};
	
	Item item6 = {
		item6.index = 4
	};
	
	listInsert(&L,1,&item1); 
	listInsert(&L,2,&item2); 
	listInsert(&L,3,&item3); 
	listInsert(&L,4,&item4);  
	CreateListHead(&L, &item5);
	CreateListTail(&L, &item6);	
	
	int length = getListLength(&L);	
//	printf("length=%d\n",length); 
	listTraverse(&L);  //显示 
/*	
	printf("\n");
	linkList n = ListReverse2(&L); //翻转 
	listTraverse(&n);  //显示 
	
	
	Item item5;
	listDelect(&L,1,&item5);
	int length1 = getListLength(&L);	
	printf("length1=%d\n",length1); 
	listTraverse(&L);	
*/
	Node * getnode ;
 	getnode = getNode(&L, 2); 
	printf("\n%d\n", getnode->nextNode->item.index);

	/*
	Item  i;
	GetNthNodeFromBack(&L, 2,&i) ; 测试单链表倒数第N个结点值
	printf("\n");
	printf("%i",i.index);
	*/
	
	/*
	Item i;
	GetMidNode(&L, &i); 测试中间节点 
	printf("\n");
	 printf("%i",i.index);
	 */
	 
	 /*
	 RemoveDupNode(&L); 测试删除重复节点 
	 printf("\n");
	  listTraverse(&L);
	  */
	  
	  /*
	  BulidListLoop(&L,2);
	  int i = hasLoop1(&L); 测试建环 检测是否有环 
      printf("\n%d",i)	;
	  */	
//	int index = locateElem(L,5);
//	printf("%d",index);	
	
	ClearList(&L);	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值