数据结构:线性表之带头结点单链表

之前跟着朱老师写的一个带头结点的:https://blog.csdn.net/weixin_42072280/article/details/82722253

创建链表时有两种方法,

一种是先初始化(创建一个空链表),然后对这个空链表进行结点输入,创建链表;这个时候,由于已经有了头结点,将其传入,直接在头结点的后面进行操作;

另外一种是将初始化和创建链表放到一个函数里,这时候传入的链表就什么都没有,连头结点也没有;先创建头结点,让传入的指针指向头结点,接着继续输入数据;  也有的书上是什么都不传入,最后生成一个链表后传出这个链表。

插入找前驱(第k个位置的前驱) 删除找前驱

//这个要从头结点开始

//如果在第1个位置插入,前驱就是头结点  

 

 for(pre = (*L); pre && i < k-1; i++){ 
        pre = pre->next;  
    }
    if(!pre){
        printf("您输入的位置大于表长!\n");
    } 

//这个要从头结点开始

//如果要删除第1个位置的结点,前驱就是头结点

  

 for(pre = (*L); pre->next && i < k-1; i++){  //寻找第k-1个结点 
        pre = pre->next;  
    }
    if(pre->next == 0){
        printf("您输入的位置大于表长!\n");
    } 

这几天写的这些个程序还有一个小缺陷,就是那个要修改链表数据的形参中,并不需要使用**L,用*L就可以;因为即使这个是传值,但是传的是指针的值,指针指向的内容是不变的。

#include
#include

typedef unsigned char  boolean;
#define  TRUE    1
#define  FALSE   0


typedef int ElemType; 
 
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode;

/*
//有些书上描述链表这样子描述,就是多定义了一个指向结点的指针而已 
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode, *LinkList;   
*/

void initLinkList(LNode **L);    //初始化的意思是构造一个空链表 
void createLinkList(LNode **L);  //尾插法 由于之前已经初始化建立了空链表,所以这个函数传入的链表就直接加有效数据结点就可以了 
void createLinkList2(LNode **L);  //头插法   尾插法需要一个指针,始终指向末结点  头插法则不用
//输出链表 
void printLinkListData(LNode *L);
//查找 
ElemType getElem(LNode *L, int k);  //找出带头结点单链表中第i个位置的结点的数据
LNode *getElem2(LNode *L, int k);    //找出带头结点单链表中第i个位置的结点的指针
LNode *locateElem(LNode *L, ElemType x);  //找到带头结点单链表中值为x结点的指针 
//插入
void insertElem(LNode **L, int k, ElemType x);   在带头结点单链表中第i个位置上插入新结点
//这就意味着是前插,但是所有的前插都是找到该结点的前驱结点,然后再进行后插 
//删除 
void deleteElem(LNode **L, int k);
boolean isEmpty(LNode *L);
int lengthOfLinkList(LNode *L);  //链表长度 





int lengthOfLinkList(LNode *L){
	int i = 0;
	LNode *p;
	
	for(p = L; p->next; i++){
		p = p->next;
	}
	return i;
} 


boolean isEmpty(LNode *L){
	return (L->next == 0);
}


void deleteElem(LNode **L, int k){
	LNode *pre = NULL;  //被删除结点的前驱结点 
	LNode *p = NULL;    //指向被删除结点 
	int i = 0;

/*  错了 
//删除的找前驱和插入的找前驱不一样
//若要插入到表长的后一个元素,则可以找前驱到表长的最后一个元素
//但是删除表长的后一个元素,前驱就不能定位了 
	//找前驱结点
	if(k < 1){
		printf("您输入的位置有误!\n");
	}
	for(pre = (*L); pre && i < k-1; i++){  //寻找第k-1个结点 
		pre = pre->next;  //这个要从头结点开始,因为是在找前驱,如果在第1个位置插入,前驱就是头结点 
	}
	if(!pre){
		printf("您输入的位置大于表长!\n");
	} 
	 
	p = pre->next;   //p指向要删除的结点 
	pre->next = p->next;
	free(p); 
	printf("删除完毕!\n");
*/
	//找前驱结点
	if(k < 1){
		printf("您输入的位置有误!\n");
	}
	for(pre = (*L); pre->next && i < k-1; i++){  //寻找第k-1个结点 
		pre = pre->next;  //这个要从头结点开始,因为是在找前驱,如果在第1个位置插入,前驱就是头结点 
	}
	if(pre->next == 0){
		printf("您输入的位置大于表长!\n");
	} 
	 
	p = pre->next;   //p指向要删除的结点 
	pre->next = p->next;
	free(p); 
	printf("删除完毕!\n");

} 

//这就意味着是前插,但是所有的前插都是找到该结点的前驱结点,然后再进行后插 
void insertElem(LNode **L, int k, ElemType x){
	LNode *pre = NULL;  
	LNode *p = NULL;    //指向新结点 
	int i = 0;

/*	
	//找前驱结点(这个方法是在已经有了getElem2这个函数的基础上进行的) 
	if(k < 1){
		printf("您输入的位置有误!\n");
	}else if(k == 1){     //}else if(k = 1){
		pre = *L;
		//printf("**\n");
	}else{
		pre = getElem2(*L, k-1);
		//printf("*\n");
	} 
	//printf("pre->data=%d\n", pre->data);
*/
	//找前驱结点
	if(k < 1){
		printf("您输入的位置有误!\n");
	}
	for(pre = (*L); pre && i < k-1; i++){  //寻找第k-1个结点 
		pre = pre->next;  //这个要从头结点开始,因为是在找前驱,如果在第1个位置插入,前驱就是头结点 
	}
	if(!pre){
		printf("您输入的位置大于表长!\n");
	} 
	
	//为新结点开辟空间
	p = (LNode *)malloc(sizeof(LNode));
	p->data = x;
	p->next = pre->next;
	pre->next = p; 
	printf("插入完毕!\n");
} 

//从单链表第一个结点开始,由前往后依次比较表中各结点数据域的值,若某结点数据域的值等于x,则返回该结点的指针;
//若整个单链表中没有这样的结点,则返回NULL 
LNode *locateElem(LNode *L, ElemType x){
	LNode *p = L->next;
	
	while(p && p->data != x){
		p = p->next;
	} 
	
	return p;  //返回值为x的结点的指针,如果没有这样的值,p=NULL,直接返回p即可
} 

//在单链表中从第一个结点出发,顺指针next域逐个往下搜索,直到找到第k个结点为止,否则返回最后一个结点指针域NULL 
LNode *getElem2(LNode *L, int k){
	int i = 1;    //计数器
	LNode *p = L->next; 
	
	if(k < 1){
		printf("您输入的位置有误!\n");
		return ;
	}
	
	while(p && i < k){
		p = p->next;
		i++;
	}
	
	return p; //返回第k个结点的指针,如果k大于表长,p=NULL,直接返回p即可 
	
} 

ElemType getElem(LNode *L, int k){
	int i = 1;    //计数器
	LNode *p = L->next; 
	
	if(k < 1){
		printf("您输入的位置有误!\n");
		return ;
	}
	
	while(p && i < k){   //寻找第k个结点 
		//printf("p->data=%d\n", p->data);
		p = p->next;
		i++;
	}
	
	if(!p){
		printf("您输入的位置大于单链表中数据的长度!\n");
		return;
	}
	return p->data;
	
} 

void printLinkListData(LNode *L){
	LNode *p;
	
	p = L->next;  //p指向第一个有效结点
	while(p){
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n"); 
} 

void createLinkList2(LNode **L){        //头插 
	LNode *p;           //p指向新结点 
	ElemType data;
	
	*L = (LNode *)malloc(sizeof(LNode));
	(*L)->next = NULL;
		
	printf("请输入数据:\n");
	scanf("%d", &data);
	while(data != 9999){   //输入9999表示结束 
		p = (LNode *)malloc(sizeof(LNode));
		p->data = data;
		p->next = NULL; 
		
		p->next = (*L)->next;
		(*L)->next = p;
		
		scanf("%d", &data);
	}
	
}

//下面的这个创建链表的方法,是把初始化和创建链表放到了一起,即传入的链表什么都没有,连头指针都没有
void createLinkList(LNode **L){  //尾插   需要增加一个指针,指向末结点 
	LNode *p;           //p指向新结点 
	LNode *q;   //q始终指向末结点 
	ElemType data;
	
	*L = (LNode *)malloc(sizeof(LNode));
	(*L)->next = NULL;
	
	q = *L;
	
	printf("请输入数据:\n");
	scanf("%d", &data);
	while(data != 9999){   //输入9999表示结束 
		p = (LNode *)malloc(sizeof(LNode));
		p->data = data;
		p->next = NULL; 
		
		q->next = p;
		q = p;
		
		scanf("%d", &data);
	}
	
}

/*
void createLinkList(LNode **L){
	LNode *p;           //p指向新结点 
	LNode *q = *L;   //q始终指向末结点 
	ElemType data;
	
	printf("请输入数据:");
	scanf("%d", &data);
	while(data != 9999){   //输入9999表示结束 
		p = (LNode *)malloc(sizeof(LNode));
		p->data = data;
		p->next = NULL; 
		
		q->next = p;
		q = p;
		
		scanf("%d", &data);
	}
}


void initLinkList(LNode **L){
	if(*L != NULL){
		printf("该指针已经指向一个有效链表!\n"); 
	}else{                    
		*L = (LNode *)malloc(sizeof(LNode)); 
		(*L)->next = NULL;
	}
}
*/

void main(void){
	//LNode list = {0};   //这样子的话,直接定义了一个结点,并且赋初值为0,就相当于定于了一个空链表 
	LNode *list = NULL;   //这样子的话,只是定义了一个指针,并没有具体的开辟结点空间,所以需要初始化,构造一个空链表
	
	
	createLinkList(&list); 		
	printLinkListData(list);

	//printf("第%d个地方的值为:%d\n", 2, getElem(list, 2));	
	//printf("第%d个地方的值为:%d\n", 2, (getElem2(list, 2))->data);
	//printf("值为%d的结点的指针所指向的值为:%d\n", getElem(list, 2), (locateElem(list, getElem(list, 2)))->data);

	//insertElem(&list, 6, 6);
	//printLinkListData(list);
	
	deleteElem(&list, 5);
	printLinkListData(list);

	printf("链表是否为空:%d\n", isEmpty(list));

	printf("链表长度为:%d\n", lengthOfLinkList(list));







}

 

你可能感兴趣的:(数据结构与算法,数据结构,线性表,带头结点,单链表)