数据结构(二)链表1:链式存储的基本操作

用任意储存空间存放线性表中的元素。储存空间可以是连续,也可以是非连续的。


节点:数据域,指针域。数据域:节点本身的信息。指针域:指向直接后继元素的地址。

节点的逻辑顺序和物理顺序不一定相同


链表:(线性表中的)数据元素按照逻辑顺序链接在一起。单链表(线性链表):指针域只有一个。


头结点:在首节点(第一个节点)之前的节点。(在第一个节点之前插入节点和删除第一个节点)


空链表:只带头结点的链表,头结点的指针域为NULL。


头指针:指向链表中第一个节点的指针,一般是链表的名字(具有标识作用)


注意:

1.节点的地址存放在其直接前驱节点的指针域中。
   由于第一个节点没有直接前驱节点,所以用头节点的指针指向第一个节点。(头结点的数据域一般存放线性表的长度)
由于最后一个节点没有直接后继节点,所以将最后一个节点的指针域置为空NULL。


2.存取链表必须从头指针开始,头指针指向链表中的第一个节点,通过头结点可以访问链表中的每一个元素。


3.一般情况下,只关心链表中节点的逻辑顺序,并不关心它的实际存储位置。


4.节点的逻辑顺序和物理顺序不一定相同。


1.链表的定义:

#include <iostream>
#include <cstdlib>
//#include<bits/stdc++.h>

using namespace std;

#define MAXSIZE 100
//const int MAXSIZE=(100);

typedef struct node {
	int data;
	node *next;
}Listnode,*Linklist;  //Listnode链表的节点类型 Linklist指向链表节点的指针类型
//Linklist l=Linknode *l;  l指向单链表的指针类型

//Linklist类型head单链表的头指针
//Listnode *p指向某一节点的指针p

//p->data  /  (*p).data  数据域
//p->naxt  /  (*p).next  指针域


2.初始化链表:

//初始化链表
void Initlist(Linklisk &head) {
	//为头结点开辟储存空间,并将头结点的指针域置为NULL
	if(!(*head=new node)
		//if(!(*head=(Linklist)malloc(sizeof(Listnode))))
		//new不能追加储存空间,malloc可以
		exit (-2);
	(*head)->next=NULL;
}


3.链表的创建:创建链表有两种方法:头插法(倒序输入),尾插法(正序输入)

//创建链表有两种方法:头插法(倒序输入),尾插法(正序输入)
//创建链表(对p:头结点的直接后继:头插法;尾节点的直接后继:尾插法)
//头插法:
//建立头结点,头结点的next域置为NULL;
//建立新节点p,将头结点head的直接后继置为p
//情况例如:
//head-p3-p2-p1
//head-p4-p3-p2-p1
//head-p5-p4-p3-p2-p1
//新插入的数在头结点的后面,在前一个插入节点的前面
Linklist Create() {
	int ch;
	Linklist head,p;

	head=new node;
	head->next=NULL;

	while((ch=getchar())!='\n') {
		p=new node;
		p->data=ch;
		p->next=head->next;
		head->next=p;
	}
	return head;
}

//尾插法
//建立头结点,并将头结点的next置为NULL
//建立新节点p,t,新节点t始终指向最后一个元素
//将节点t的直接后继指向p,最后t指向p
//情况例如:
//head-p1-p2-p3
//head-p1-p2-p3-p4
//head-p1-p2-p3-p4-p5
Linklist Create() {
	int ch;
	//Linklist head,p,t;

	Linklist head=new node;
	head->next=NULL;
	Linklist t=head;

	while((ch=getchar())!='\n') {
		Linklist p=new node;
		p->data=ch;
		p->next=NULL;
		t->next=p;
		t=p;
	}
	return head;
}

4.判断链表是否为空

//判断链表是否为空
bool Isempty(Linklist head) {
	//head->next==NULL  头指针的next域为NULL
	if(head->next==NULL)  return false;
	else return true; 
}


5.找出链表中第i个节点的元素

//找出链表中第i个节点的元素
Listnode *Geteleme(Linklisk head,int i) {
	//判断i是否合法
	//判断链表是否为空
	if(i<1)  exit (-2);
	else if(head->next==NULL)  exit (-2);
	else {
		Listnode *p=head->next;
	    int j=1;
		
		while(p  &&  j<i) {
			p=p->next;
			j++;
		}
		
		if(j==i)  return p;  //成功后返回对应节点的指针
        else  return NULL;		
	}
}



6.找出元素值为e的节点

//找出元素值为e的节点
Listnode *Locateelem(Linklist head,int e) {
	//新建立的节点的数据域元素等于e
	Listnode *p=head->next;
	
	while(p) {
		if(p->data==e)  break;
		else p=p->next;
	}
	return p;  //成功后返回对应节点的指针
}<pre name="code" class="cpp">//删除链表中的第i个节点元素值e
int Deleteelem(Linklist head,int i,int e) {
	//1.找到第i个节点的直接前驱节点pre
	//2.新生成的节点p指向pre节点的直接后继节点p=pre->next,即第i个节点;
	//3.将e的值赋值给p的数据域p->data;
	//4.删除第i个节点,即pre->next=p->next;
	Listnode *pre=head;
	int j=0;

	//pre->next->next就是判断是最后一个节点,pre=pre->next; p=pre->next->next;p指针指向的不是NULL指针域
	while(pre->next  &&  j<i-1  &&  pre->next->next) {  //找到前驱节点   
		pre=pre->next;
		j++;
	}
	Listnode *p=new Listnode;
	if(!p)  return 0;
	else {
		e=p->data;
		//删除节点操作
		p=pre->next;
		pre->next=p->next;
		//释放p指向的节点的空间
		delete []p;
		return 1;
	}
}

 
 

7.找出元素值为e的节点的序号

//找出元素值为e的节点的序号
Listnode *Locatedpos(Linklist head,int e) {
	//新建立的节点的数据域元素等于e
	//判断链表是否为空
	Listnode *p=head->next;
	int j=1;
	while(p) {
		if(p->data==i) return i;
		else {
			p=p->next;
			i++;
		}
	}
	if(!p)  exit (-2);
}


8.在第i个位置插入元素e

//在第i个位置插入元素e
int Insertelem(Linklist head,int i,int e) {
	//储存e的节点为p,则要将p指向的节点插入到pre和pre->next之间
	//语句为:p->next=pre->next;pre->next=p;
	//算法思路:
	//1.找到第i个节点的直接前驱节点,然后生成一个新节点p  
	//2.将e的值赋给p的数据域p->data
	//3.将新节点p插入到原链表中
	Listnode *pre=head;
	int j=0;
	while(pre->next  &&  j<i-1) {  //找到前驱节点
		pre=pre->next;
		j++;
	}

	Listnode *p=new Listnode;
	if(!p)  return 0;
	else {
		p->data=e;
	    //插入节点操作
	    p->next=pre->next;
	    pre->next=p;
	    return 1;
	}	
}


9.删除链表中的第i个节点元素值e

//删除链表中的第i个节点元素值e
int Deleteelem(Linklist head,int i,int e) {
	//1.找到第i个节点的直接前驱节点pre
	//2.新生成的节点p指向pre节点的直接后继节点p=pre->next,即第i个节点;
	//3.将e的值赋值给p的数据域p->data;
	//4.删除第i个节点,即pre->next=p->next;
	Listnode *pre=head;
	int j=0;

	//pre->next->next就是判断是最后一个节点,pre=pre->next; p=pre->next->next;p指针指向的不是NULL指针域
	while(pre->next  &&  j<i-1  &&  pre->next->next) {  //找到前驱节点   
		pre=pre->next;
		j++;
	}
	Listnode *p=new Listnode;
	if(!p)  return 0;
	else {
		e=p->data;
		//删除节点操作
		p=pre->next;
		pre->next=p->next;
		//释放p指向的节点的空间
		delete []p;
		return 1;
	}
}


10.链表的遍历

//链表的遍历
void Print(Linklist head) {
	//输出p->data
	Listnode *p=head->next;

	while(p) {
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<endl;
}


11.求链表的长度

//求链表的长度
int Length(Linklist head) {
	//单链表元素的个数
	Listnode *p=head->next;
	int i=0;

	while(p) {
		i++;
		p=p->next;
	}
	return i;
}


12.销毁链表

//销毁链表
void Clean(Linklist head) {
	//删除每一个元素,并释放节点空间
	Listnode *p=head->next;

	while(p) {
		Listnode *q=p;
		free(q);
		p=p->next;
	}
}

13.主函数

//主函数
int main () {
	Linklist head;
	Initlist(head);
	head=Create();
	Isempty(head);

	Length(head);
	Print(head);
	Clean(head);
	rteurn 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值