1. 程式人生 > >帶頭結點的連結串列實現通訊錄

帶頭結點的連結串列實現通訊錄

關於連結串列使用二級指標或者一級指標引用的問題:

     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;
}