第一章---线性表之单链表的操作

#include <iostream>
#include <stdlib.h>
using namespace std;
typedef int DataType;   //使int重命名为DataType 
DataType flag = 0;   //flag是用来判断神魔时候输入数据结束 
typedef struct Lnode{
	DataType data;  //定义DataType为int ,存储结构为顺序存储 
	struct Lnode *next;
}Lnode,*LinkList; 

/*
	1.链表的创建方法  头插法,尾插法
	2.链表分类  单链表,循环链表,双向链表
	3.默认都建立带头节点的链表   头节点的数据域不定义数据   head要摸为NULL,要摸为第一个结点的地址 
	4.单链表的创建方法
	  头插法:数据输入和输出顺序相反
	  尾插法:数据输入顺序和输出顺序相同 
	5.基本操作     查找操作是链表的核心 决定着其他各项依赖于查找的方法的性能 插入和删除都依赖于查找操作 
	单链表默认都创建带头结点的  因为再进行各种操作时 比如求长度,不带头结点的单链表我们要特殊考虑第一个节点是不是空表 
	而带头结点的就不用考虑第一个节点
		1.求带头结点的表长:int length_LinkList1(LinkList head) 
		2 求不带头结点的表长:int length_LinkList(LinkList head) 
		//下面方法都是操作默认带头结点的单链表 
		3.按序号查找操作(返回第i个位置的指针地址):LinkList get_LinkList(LinkList head,int i) 
		4.按值查找操作(返回第i个位置的指针地址): LinkList locate_LinkList(LinkList head,DataType x) 
		5.插入结点操作(分为前插节点和后插节点)(在第i个结点之前插入节点x):int insertP_LinkList(LinkList head,int i,DataType x) 
		6.插入结点操作(分为前插节点和后插节点)(在第i个结点之后插入节点x):int insertT_LinkList(LinkList head,int i,DataType x)  
		7.删除结点操作(删除第i个结点):int del_LinkList(LinkList head,int i) 
		8.多节点删除运算(从第i个结点开始连续删除k个结点):delK_LinkList(LinkList head,int i,int k) 
*/
//头插法  不带头节点的单链表 
LinkList create_LinkList(){
	LinkList head;
	head=NULL;  //创建一个头节点为空的链表
	LinkList s;
	DataType x;
	cout<<"请输入x的值:";
	cin>>x; 
	while(x!=flag){
		s=(LinkList)malloc(sizeof(Lnode));
		s->data=x;
		s->next=head;
		head=s;
		cin>>x; 
	} 
	return head;
} 

//不带头结点的显示链表方法 
void out_LinkList(LinkList head){
	LinkList p=head;
	while(p->next!=NULL){
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<p->data;
} 

//头插法 带头节点的单链表
LinkList create_LinkList1(){
	LinkList p,head;
	p->next=NULL; //设p是头节点
	//p->data=0; //表示头节点的数据 
	head=p;   //head是一个游标
	LinkList s;
	DataType x;
	cout<<"请输入x的值:"; 
	cin>>x;
	while(x!=flag){
		s=(LinkList)malloc(sizeof(Lnode));
		s->data=x;
		s->next=head;
		head=s;
		cin>>x;
	}
	return head;
} 

//带头结点的显示单链表的方法   不输出头结点的数据域 
void out_LinkList1(LinkList head){
	LinkList p=head;
	while(p->next!=NULL){
		cout<<p->data<<" ";
		p=p->next; 
	}
} 

//尾插法  不带头结点
LinkList create_LinkListR(){
	LinkList head,s,p;
	head=p=NULL;
	cout<<"请输入x的值:";
	DataType x;
	cin>>x;
	while(x!=flag){
		s=(LinkList)malloc(sizeof(Lnode));
		s->data=x;
		if(head==NULL){
			//说明原来是空表
			p=head=s; 		
		}else{
			p->next=s;
			p=s;
		}
		cin>>x; 
	}
	p->next=NULL;
	return head; //返回头结点的指针 
} 

//尾插法 带头结点
LinkList create_LinkListR1(){
	LinkList head,p,s;
	//head->data=100;  可以给头结点数据域赋值验证 
	head->next=NULL;  //带头节点
	p=head;
	DataType x;
	cout<<"请输入x的值:";
	cin>>x;
	while(x!=flag){
		s=(LinkList)malloc(sizeof(Lnode));
		s->data=x;
		p->next=s;
		p=s;
		cin>>x;
	} 
	p->next=NULL;
	return head;
} 

//求带头结点的单链表的长度 (头节点不算入总长度) 
int length_LinkList1(LinkList head){
	//设置一个移动指针p和计数器count
	LinkList p=head;
	int count=0;
	while(p->next!=NULL){
		p=p->next;
		count++;
	}
	return count;
}

//求不带头结点的单链表的长度  要考虑第一个节点 
int length_LinkList(LinkList head){
	//设置一个移动的指针和一个计数器 
	LinkList p=head;
	int count=0;
	if(p==NULL){
		cout<<"单链表为空!"<<endl;
		return 0;
	}else{
		count=1;
		while(p->next!=NULL){
			p=p->next;
			count++;
		}
		return count;
	}
} 

//                   带头结点的   不需要判断是不是空表 


//按序号查找操作  返回i位置的指针地址 
LinkList get_LinkList(LinkList head,int i){
	//判断i位置链表有没有 
	LinkList p=head;
	int count=0;
	//这是一种思想,用循环包裹几种结果,在循环体外判断 
	while(p->next!=NULL && i>count){
		//循环结束只有两种情况,要摸链表到头了没找到,要摸找到了
		p=p->next;
		count++; 
	}
	if(i==count){ //找到了的情况 
		return p;
	}else{  //到头了的情况 
		return NULL;
	}
}

//按值查找
LinkList locate_LinkList(LinkList head,DataType x){
	LinkList p = head;
	while(p->next!=NULL){
		p=p->next;
		if(p->data==x)
			return p;
	}
	return NULL;
}

//前插节点  插入操作依赖于查找操作
//单链表注意事项: 前置插入操作要找到待插入结点的前面一个结点 
//如果链表是双向链表就没有这个烦恼了,直接找到位置插入即可 
int insertP_LinkList(LinkList head,int i,DataType x){
	LinkList p = head;  //保护头节点  重点  每个方法里面必须都写
	LinkList q = get_LinkList(p,i-1);
	LinkList s; //创建待插入节点 
	s=(LinkList)malloc(sizeof(Lnode));
	s->data=x;
	if(q!=NULL){  //查找成功  找到了第i-1个结点 
		s->next=q->next;
		q->next=s;
		return 0; //插入成功 
	} else{
		//cout<<"第i个结点不存在,不能插入第i个节点之前!"<<endl;
		return -1;
	}
} 

//后插节点  
//单链表注意事项: 后置插入操作要找到待插入节点的后一个节点 
//如果是双向链表就没有这个烦恼了 
int insertT_LinkList(LinkList head,int i,DataType x){
	LinkList p = head;  //保护现场    从汇编处学到的编程经验 
	LinkList q = get_LinkList(p,i);  //查找后一个节点 
	LinkList s; //创建待插入节点 
	s=(LinkList)malloc(sizeof(Lnode)); 
	s->data=x;
	if(q==NULL){
		cout<<"未找到第i个节点!"<<endl;
		return -1;
	}
	if(q->next==NULL){//当前是最后一个节点 
		q->next=s;
		s->next=NULL;
		return 0;
	}
	if(q->next!=NULL){
		s->next=q->next;
		q->next=s;
		return 0;
	}
}

//删除结点  删除第i个结点  要找到第i-1个结点 
int del_LinkList(LinkList head,int i){
	LinkList p = head;
	LinkList q = get_LinkList(p,i-1);  //查找第i-1个结点 
	if(q==NULL || q->next==NULL){  //不存在有两种情况 
		cout<<"第i个结点不存在!删除失败!"<<endl; 
		return -1;
	} else{ //存在有两种情况 
		if(q->next->next==NULL){//恰巧要删除的是最后一个结点 
			free(q->next);
			q->next=NULL;
			return 0;
		}else{  //要删除的结点在链表内部
			 LinkList s;
			 s=q->next;
			 q->next=s->next;
			 free(s);
			 return 0;
		}
	}
 } 
 

int main(int argc, char** argv) {
	LinkList head = create_LinkListR1();
	out_LinkList(head); 
	cout<<endl; 
	cout<<length_LinkList1(head)<<endl;
	cout<<"插入操作:"<<endl;
	int i = insertT_LinkList(head,3,100);
	if(i==0){
		out_LinkList(head);
	}else{
		cout<<"插入失败!"<<endl;
	}
	int j = del_LinkList(head,4);
	if(j==0){
		out_LinkList(head);
	}else{
		cout<<"error"<<endl;
	}
	free(head);
	return 0;
}

  

原文地址:https://www.cnblogs.com/nanfengnan/p/14378630.html