链表总结

 


 一、单链表

 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为节点列表,因为链表是由一个个节点组装起来的;其中每个节点都有指针成员变量指列表中的下一个节点;

   列表是由节点构成,由head指针指向第一个成为表头的节点而终止于最后一个指向nuLL的指针;

1.建立链表(尾插法):

尾插法的基本思想:
1.生成一个节点,将读入的数据存放到新节点的数据域中
2.把新节点插到当前链表的尾节点之后
3.重复上述过程,直至输入结束标志

 

尾插法读入数据的顺序和线性表的逻辑顺序是相同的

void creat_list( Node* &head) {  //传入指向表头的指针,这个指针要保存下来。 注意Node* &, 是Node* 类型的引用
	
	Node *pre,*newNode;
	head = pre = new Node;  //生成表头结点

	newNode = new Node;     //建立新节点
	cin>>newNode->num;      //输入新节点的值
	while(newNode->num) {   //判断输入结束的条件
		pre-> next = newNode;     //上一个节点连接新节点
		pre = newNode;            //因为马上要申请新空间,此时的新节点即将变成“上一个节点”,保存给pre
		newNode = new Node;		  //再次申请新空间
		cin >> newNode->num;      //输入值
	}
	pre->next = NULL;   //结束后,将单链表最后一个节点rear指针置为空,标志着结束
} 


2.建立链表(头插法)

头插法的基本思想:
1.生成一个节点,将读入的数据存放到新节点的数据域中
2.把新节点作为第一个表节点查到单签链表头节点之后
3.重复上诉过程,直至输入结束标志为止

 

头插法读入数据的顺序和线性表的逻辑顺序是相反的。

void creat_head(Node* &head) {
	Node *newNode;        
	head = new Node;        
	head->next = NULL;
	newNode = new Node;
	cin>>newNode->num;    //输入数据
	while(newNode->num){
		newNode->next = head->next;
		head->next = newNode;
		newNode = new Node;
		cin >> newNode->num;
	}
}


 

3.单链表查找:按值查找

Node* search_value(Node *head, int x){  //x为要查找的值
	Node *p=head->next;
	while(p!=NULL && p->num!=x)
		p = p->next;
	if(p->num ==x )
		return (p);
	return NULL;
}


4.单链表查找:按位置查找

Node* search_local(Node *head, int i) {  //i为要查找的位置
	Node *p=head;
	int count=0;
	while(p->next!=NULL && count<i) {
		p = p->next;
		++count;
	}
	if(count==i)
		return (p);
	return NULL;
}


5.单链表插入:前插(后插)

操作过程:
1.生成一个新节点newNode,将值x赋给新节点newNode的数据域
2.从表头节点开始,查找p的前驱节点q
3.修改有关节点的指针域,将newNode指针域指向p节点,q节点指向newNode

Node* inset_front(Node *head,int i,int x){  //x为要插入的值,i是位置
	Node *p,*newNode;
	newNode = new Node;       //申请新空间
	newNode->num = x;		  //赋值
	p = search_local(head,i-1);   //只要把i-1改成i,就变成了插在i的后面(后插法)
	newNode->next = p->next;
	p->next = newNode;
	return head;
}


6.单链表的删除(删除链表中的值x)

操作过程:
1.假设有两个节点pre和p,pre是p的前驱节点,p为要删除的节点
2.找pre,从链表head的头结点开始,一次向后进行搜索,当pre-next = p时,找到
3.修改pre-next = p-next,把p的前驱节点指向p的后继节点,并且删除空间

Node* delete_link(Node *head,int x){
	Node *pre,*p;   //pre存p的前驱节点
	p = head;
	while(p!=NULL && p->num!=x) {
		pre=p;
		p = p->next;
	}
	if(p!=NULL) {
		pre->next = p->next;
		delete (p);
		return head;
	}
	else {
		cout<<"要删除的值不存在\n";
		return NULL;
	}
}


 

二、循环列表

循环链表:表中最后一个节点的指针域不再是空,而是指向第一个节点,整个链表形成一个环。

特点:从表中任一节点出发,就可搜寻到其他所有节点

作用:在许多实际应用中,对链表的操作运算是在表头、表尾进行的,这时可以改变链表的标识方法,不用头指针
   而用指向尾节点的尾指针rear来标识,以提高效率。
  
和单链表的比较:
   单链表中,找到第一个元素时间为O(1),最后一个元素为O(n);
   而应用循环链表,则找到最后一个元素为O(1),由于最后一个元素指向第一个元素,因此找到第一个元素也为O(1)

运算: 循环链表与单链表的运算基本一致,区别在于判断遍历表完成条件不同,单链表判断当前指针域是否为空,而循环
   链表判断当前节点指针域是否为表头指针。

 

//下面以查找运算为例

//下面以查找运算为例

Node* search_value(Node *head, int x){  //x为要查找的值
	Node *p=head->next;
	while(p->next!=head && p->num!=x)   // p->next!=head
		p = p->next;
	if(p->num ==x )
		return (p);
	return NULL;
}


 

 

三、双向链表

 双向链表:指沿着前驱和后继方向都能遍历的线性链表。
 其每个节点都有两个指针域:一个指向其后继节点,另一个指向其前驱结点。

 

双向链表的节点类型定义为:

struct Dnode{
	int data;             //data储存表中的元素 
	Dnode *next,*prior;   //next指向后一节点指针,prior指向前一节点指针
};

 

双向链表优点: 双向链表既有向前的指针域,又有向后的指针域,这就使得双向链表的前插和后插
   以及删除操作都很方便,只需要修改几个节点的指针域,而不必进行大量的数据交换和遍历操作

// 节点类型
struct Dnode{ 
	int data;             //data储存表中的元素 
	Dnode *next,*prior;   //next指向后一节点指针,prior指向前一节点指针
};

//双向链表的前插(在某节点p之前插入一个新节点s)
Dnode *insert_before(Dnode *head,Dnode *p, int x){
	Dnode *s;            //s为要插入的节点
	s = new Dnode;  //建立新节点
	s->data = x;   //给s节点的数据域赋值
	s->next = p;				//步骤1:将节点s的后继指针指向p;
	s->prior = p->prior;		//步骤2:将节点s的前驱指针指向节点p的前驱节点
	p->prior->next = s;			//步骤3:将p的前驱结点的后继指针修改为指向新节点s;
	p->prior = s;				//步骤4:将节点p的前驱指针修改为指向新节点s.
	return head;
}


//双向链表的后插(在某节点p之后插入一个新节点s):
Dnode *insert_back(Dnode *head,Dnode *p, int x){
	Dnode *s;            //s为要插入的节点
	s = new Dnode;		 //建立新节点
	s->data = x;		 //给s节点的数据域赋值
	s->next = p->next;			//步骤1:将节点s的后继指针指向p;
	s->prior = p;				//步骤2:将节点s的前驱指针指向节点p的前驱节点
	p->next->prior = s;			//步骤3:将p的前驱结点的后继指针修改为指向新节点s;
	p->next = s;				//步骤4:将节点p的前驱指针修改为指向新节点s.
	return head;
}


//双向链表节点的删除:
Dnode *delete_Dnode(Dnode *head,Dnode *p){
	if(p != NULL){
		p->prior->next = p->next;   //步骤1:将p的前驱节点的后继指针改为指向p的后继
		p->next->prior = p->prior;  //步骤2:将p的后继结点的前驱指针改为指向p的前驱
		delete (p);					//步骤3:释放p的存储空间
		return head;		//返回带头结点双向链表的头指针
	}
	else
		return NULL;
}


 


——      生命的意义,在于赋予它意义。 

                   原创  http://blog.csdn.net/shuangde800  , By   D_Double




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表是一种常用的数据结构,用于存储一系列元素。C语言中,链表是通过指针来实现的,每个节点包含数据和指向下一个节点的指针。 以下是链表的基础知识总结: 1. 链表的定义: ```c struct Node { int data; struct Node* next; }; ``` 其中,data 表示节点存储的数据,next 表示指向下一个节点的指针。 2. 链表的操作: - 创建节点: ```c struct Node* createNode(int data) { struct Node* node = (struct Node*) malloc(sizeof(struct Node)); node->data = data; node->next = NULL; return node; } ``` - 插入节点: ```c void insertNode(struct Node* head, int data) { struct Node* node = createNode(data); node->next = head->next; head->next = node; } ``` 其中,head 表示链表节点。 - 删除节点: ```c void deleteNode(struct Node* head, int data) { struct Node* p = head->next; struct Node* q = head; while (p != NULL) { if (p->data == data) { q->next = p->next; free(p); break; } q = p; p = p->next; } } ``` - 遍历链表: ```c void traverseList(struct Node* head) { struct Node* p = head->next; while (p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); } ``` - 销毁链表: ```c void destroyList(struct Node* head) { struct Node* p = head->next; while (p != NULL) { struct Node* q = p; p = p->next; free(q); } head->next = NULL; } ``` 3. 链表的优缺点: 链表的优点是插入和删除操作的时间复杂度为 O(1),而数组的时间复杂度为 O(n)。但是,链表的缺点是无法随机访问元素,需要遍历整个链表才能找到要查找的元素。此外,链表需要额外的空间来存储指向下一个节点的指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值