带头结点的链表实现通讯录

关于链表使用二级指针或者一级指针引用的问题:

     1、使用二级指针完全可以代替一级指针。在没有头结点的情况下必须使用二级指针,使用一级指针无效。

     2、而如果不用二级指针,直接传一个一级指针,相当于生成L的拷贝M,但是对M分配空间与L无关了。

     3、只要是修改头指针则必须传递头指针的地址,否则传递头指针值即可(即头指针本身)。这与普通变量类似,当需要修改普通变量的值,需传递其地址,否则传递普通变量的值即可(即这个变量的拷贝)。使用二级指针,很方便就修改了传入的结点一级指针的值。 如果用一级指针,则只能通过指针修改指针所指内容,却无法修改指针的值,也就是指针所指的内存块。所以创建链表和销毁链表需要二级指针或者一级指针引用。

     4、不需要修改头指针的地方用一级指针就可以了,比如插入,删除,遍历,清空结点。假如头指针是L,则对L->next 及之后的结点指针只需要传递一级指针。

     5、比如一个结点p,在函数里要修改p的指向就要用二级指针,如果只是修改p的next指向则用一级指针就可以了


     函数中传递指针,在函数中改变指针的值,就是在改变实参中的数据信息。但是这里改变指针的值实际是指改变指针指向地址的值,因为传递指针就是把指针指向变量的地址传递过来,而不是像值传递一样只是传进来一个实参副本。所以当我们改变指针的值时,实参也改变了。

 headlist.h:

#ifndef _HEADLIST_H
#define _HEADLIST_H

#define OK     0
#define ERROR  -1

typedef struct _node
{
	char name[10];
	int data;
	struct _node *next;
}Node;


//创建链表
Node *createList();

// 尾法插入元素
int insertLast(Node *head);

//输出通讯录内容
void display(Node *head);

//在指定位置插入元素
int insertPos(Node *head,int pos);

//根据姓名删除元素
int deleteData(Node *head,char *name);

//根据姓名修改元素ID
int modifyData(Node *head,char *name);

//根据id查找元素
int LocateElem(Node *head,int data);

//逆序
int ReverseLinkList(Node *head);
#endif

headlist.c:

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

//创建链表就是创建一个头结点
Node *createList()
{
	Node * pNode=(Node*)malloc(sizeof(Node)/sizeof(char));
	if(pNode==NULL)
	{
		printf("Failed to create header\n");
		return NULL;		//返回值类型为指针,所以用NULL
	}
	
	pNode->next=NULL;
	
	return pNode;
}
//逆序
int ReverseLinkList(Node *head)
{
	if(head==NULL)
		return ERROR;
	
	Node *tmp1=head->next;
	head->next=NULL;
	while(tmp1)
	{
		Node *tmp2=tmp1;
		tmp1=tmp1->next;
		tmp2->next=head->next;
		head->next=tmp2;
	}
	return OK;
}
//根据id查找元素
int LocateElem(Node *head,int data)
{
	if(head==NULL)
		return ERROR;
	
	Node *tmp=head;
	while(tmp)
	{
		if(tmp->data==data)
		{
			printf("找到的元素信息为:\n");
			printf("%s\n",tmp->name);
			printf("%d\n",tmp->data);
			break;
		}
		tmp=tmp->next;
	}
	
	return OK;
}
//根据姓名修改元素ID
int modifyData(Node *head,char *name)
{
	if(head==NULL)
		return ERROR;
	
	Node *tmp=head;
	while(tmp)
	{
		if(strcmp(tmp->name,name)==0)
		{
			int data;
			printf("请输入元素修改后的ID:\n");
			scanf("%d",&data);
			tmp->data=data;
			return OK;
		}
		tmp=tmp->next;
	}
	return ERROR;
}
//根据姓名删除元素
int deleteData(Node *head,char *name)
{
	if(head==NULL)
		return ERROR;
	
	Node *tmp=head;
	while(tmp->next)				//为了跨结点连接
	{
		if(strcmp(tmp->next->name,name)==0)
		{
			//tmp->next=tmp->next->next;
			//free(tmp->next);
			Node *p=tmp->next;						/* 为什么要 p  */
			tmp->next=p->next;
			free(p);
			return OK;		//正确删除,返回ok
		}
		tmp=tmp->next;
	}
	
	return ERROR;
}
//根据位置插入元素
int insertPos(Node *head,int pos)
{
	if (head == NULL)
		return ERROR;
	
	//遍历到元素的位置,准备插入
	int i;
	Node *tmp=head;
	for(i=0;i<pos-1;i++)
	{
		if(tmp==NULL)
		{
			printf("没有pos 这个位置\n");
			return ERROR;
		}
		tmp=tmp->next;
	}										//tmp遍历到pos-1处
	
	//为新结点创建空间并赋值
	Node *node=(Node*)malloc(sizeof(Node)/sizeof(char));
	if(node==NULL)						//此处 起初将Node 写成node ,malloc 没有成功,报错 "invalid next size (fast):"
		return ERROR;
	
	int data;
	char name[10];
	printf("请输入插入用户的姓名:\n");
	scanf("%s",name);
	printf("请输入插入用户的ID:\n");
	scanf("%d",&data);
	strcpy(node->name,name);
	node->data=data;
	
	//新结点的指针域指向 tmp 的后继,tmp 指向新结点node,完成插入
	node->next=tmp->next;
	tmp->next=node;
	
	return OK;
}
// 尾法插入数据
int insertLast(Node *head)
{
	if (head == NULL)
		return ERROR;
	
	//为新插入的结点创建空间并赋值
	Node * node = (Node*)malloc(sizeof(Node)/sizeof(char));
	if (node == NULL)
		return ERROR;
	
	int data;
	char name[10];
	printf("请输入好友姓名\n");
	scanf("%s",name);
	printf("请输入好友ID\n");
	scanf("%d",&data);
		
	strcpy(node->name,name);		//新结点的赋值
	node->data = data;
	node->next = NULL;
	
	// 找最后一个结点,准备插入
	Node *tmp = head;
	while (tmp->next)			
	{
		tmp = tmp->next;
	}
	
	//将尾结点的指针域指向新结点,完成尾插
	tmp->next = node;
	
	return OK;
}

void display(Node *head)
{
	if (head == NULL)
		return;			//void 类型函数返回值写法
	
	// 第一个结点
	Node *tmp = head->next;  
	while (tmp)
	{
		printf("%s\n",tmp->name);
		printf ("%d\n", tmp->data);
		tmp = tmp->next;   // 下一个元素
	}
	printf ("\n");
}

main.c

#include<stdio.h>
#include<stdlib.h>
#include "headList.h"

int main()
{
	printf("欢迎来到苏嵌教育\n");
	Node *pNode=createList();
	if(pNode==NULL)
		return ERROR;
	
	int i,pos,a,data;
	char name[10];
	for(i=0;i<3;i++)
	{
		insertLast(pNode);		//如果用二级指针,这里的实参要改为 &pNode, .c 和 .h 文件中的函数形参要改为
	}							//Node **head, 函数中 head 要改为 (*head)
	printf("尾插法后的通讯录为:\n");
	display(pNode);
	
	while(1)
	{
		printf("请选择以下功能;\n");
		printf("1.插入好友信息\n");
		printf("2.删除好友信息\n");
		printf("3.修改好友信息\n");
		printf("4.查找好友\n");
		printf("5.通讯录逆序查看\n");
		printf("6.退出\n");
		scanf("%d",&a);
		if(a>6)
			printf("无此功能\n");
		switch(a)
		{
			case 1:
			printf("请输入要插入的位置:\n");
			scanf("%d",&pos);
			insertPos(pNode,pos);
			printf("插入新元素后的通讯录为:\n");
			display(pNode);
			break;
			case 2:
			printf("请输入要删除元素的姓名:\n");
			scanf("%s",name);
			deleteData(pNode,name);
			printf("删除元素后的通讯录为:\n");
			display(pNode);
			break;
			case 3:
			printf("请输入要修改元素的姓名:\n");
			scanf("%s",name);
			modifyData(pNode,name);
			printf("修改后的通讯录为:\n");
			display(pNode);
			break;
			case 4:
			printf("请输入要查找元素的id:\n");
			scanf("%d",&data);
			LocateElem(pNode,data);
			break;
			case 5:
			ReverseLinkList(pNode);
			printf("逆序后的通讯录为:\n");
			display(pNode);
			break;
			case 6:
			exit(0);
			break;
		}
	}
	return OK;
}

猜你喜欢

转载自blog.csdn.net/kuniqiw/article/details/85466279
今日推荐