链表

典型数据结构:数组、链表、队列、栈、二叉树、Hash表、图

一、链表

1、头指针和头结点

头指针

a) 头指针是指向链表第一个结点的指针,如果存在头结点,头指针就是指向头结点的指针。

b) 头指针具有标识作用,常用头指针冠以链表的名字

c) 无论链表是否为空,头指针均不为空(对此句话不认同)。头指针是链表的必要元素。

 

头结点

a) 头结点是为了操作的统一和方便而设立的,位于第一个数据节点之前,其数据域一般无意义(也可以存放链表的长度)。

b) 有了头结点,在第一元素前插入节点和删除第一节点,其操作与其他节点的操作就统一了。

c) 头结点不是链表的必要元素。


头指针只是一个指针,没有实例化;头结点是一个实例化的节点。


2、链表的程序实现

1)注意:在main函数里面定义的linklist list; 这个地方定义的是头指针,头结点在creat()函数里面创建,头结点是占有实际空间的,需要动态分配内存。

creat1(&list,3); //由于creat1()函数需要创建头结点,而头指针(即list)需要指向头结点,list原来是空,在函数里要改变,要想保留结果必须将其指针传入函数内部。注意c语言不能引用,但是可以传递指针,此处是提取指针,不要混淆掉。插入和删除虽然会改变链表,但是不会改变头指针,所以不用定义为linklist的指针(虽然书上这样写)。

2)双链表和单链表的操作大部分相同,因为只要朝一个方向遍历就可以。构造、插入和删除函数,有区别。一般涉及3个节点,4条连接。

注意,双链表初始的时候,只有头结点,头结点的prior指针和next指针均指向自身

#include<iostream>
using namespace std;
/*
注意这里linklist是节点的指针类型,一般用于定义头指针,由于头指针具有标识作用,所以可以认为其是用来定义链表的。
*/
typedef struct node
{
	int data;
	node *next;
}node,*linklist;
/*
获取第i个元素值。注意,尽量用指针,因为C不支持引用
*/
bool getelem(linklist l,int i,int *elem)
{
	node *p = l->next;
	/*
	确定边界最好的办法就是假设一种情形,边界设
	置好的话,操作的形式会统一地很好。
	*/
	while ((i > 1)&&(p!=NULL)) 
	{
		p = p->next;
		i--;
	}

	if (p == NULL) return false;  
	*elem = p->data;
	return true;
}
/*
在第i个元素前,插入元素。
*/
bool linsert(linklist l, int i, int elem)
{
	node* p = l;
	while ((i > 1) && (p != NULL))
	{
		p = p->next;
		i--;
	}
	if (p == NULL) return false;
	/*
	C++和C动态分配存储的方式不同,malloc返回的指针是void的,必须强制转换。C++为struct提供默认的构造函数
	*/
	node *temp = (node*)malloc(sizeof(node));
	//node *temp=new node();
	temp->next = p->next;
	temp->data = elem;
	p->next = temp;
	return true;
}
/*
删除第i个元素,并将值赋给elem,删除的时候,要先保留删除位置,否则会丢失
*/

bool ldelete(linklist l,int i,int *elem)
{
	node* p = l;
	while ((i>1)&&(p->next!=NULL))
	{
		p = p->next;
		i--;
	}

	node *q = p->next; 
	if (q == NULL) return false;
	*elem = q->data;
	p->next = q->next;
	free(q);
	return true;
}

bool creat1(linklist *l, int n)  //头插
{
	*l = (node *)malloc(sizeof(node));
	(*l)->next = NULL;  //指针一定要初始化
	while (n > 0)
	{
		node *temp = (node *)malloc(sizeof(node));
		temp->next = (*l)->next;
		temp->data = n;
		(*l)->next = temp;
		n--;
	}
	return true;
}

bool creat2(linklist *l, int n)  //尾插
{
	node *tail;
	(*l) = (node *)malloc(sizeof(node));
	(*l)->next = NULL;
	tail = *l;
	while (n > 0)
	{
		node *temp = (node *)malloc(sizeof(node));
		temp->next = NULL;
		temp->data = n;
		tail->next = temp;
		tail = temp;
		n--;
	}
	return true;
}

void lprint(linklist l)
{
	node *p = l->next;
	while (p != NULL)
	{
		cout << p->data<<" ";
		p = p->next;
	}
	cout << endl;
}

int main()
{
	linklist list;  //这个地方定义的是头指针,头结点在creat函数里面创建,头结点是占有实际空间的,需要动态分配内存
	linklist list2;
	int a;
	list = NULL;
	cout << "原始:" << endl;
	creat1(&list,3); //由于,creat函数需要创建头结点,而头指针(即list)需要指向头结点,
                         //list原来是空,在函数里要改变,要想保留结果必须将其指针传入函数内
                         //部。注意c语言不能引用,但是可以传递指针,此处是提取指针,不要混淆掉。
	lprint(list);
	cout << "删除后:" << endl;
	ldelete(list,1,&a);
	lprint(list);
	cout << "插入后:" << endl;
	linsert(list,2,7);
	lprint(list);
	cout << "尾部插入方式:" << endl;
	creat2(&list2, 3);
	lprint(list2);
	system("pause");
	return 0;
}

#include<iostream>
using namespace std;
typedef struct node
{
	int data;
	node *prior;
	node *next;
}node, *linklist;
/*
第i个节点前插入元素elem
*/
bool linsert(linklist l, int i, int elem)
{
	node *q;
	node *p = l->next;;
	while ((i > 1) && (p != NULL))
	{
		p = p->next;
		i--;
	}
	if (p == NULL) return false;
	node *temp = (node*)malloc(sizeof(node));
	temp->data = elem;
	/*插入操作涉及3个节点*/
	q = p->prior;//q是第一个节点,temp是第二个节点,p是第三个节点

	q->next = temp;
	temp->prior = q;

	temp->next = p;
	p->prior = temp;
	return true;
}

bool ldelete(linklist l,int i,int *elem)
{
	node *p = l->next;
	while ((i > 1) && (p != NULL))
	{
		p = p->next;
		i--;
	}
	if (p == NULL) return false;

	node *q,*r;
	*elem = p->data;
	q = p->prior;
	r = p->next;

	q->next = r;
	r->prior = q;
	return true;
}

void creat(linklist *list,int n)
{
	(*list) = (node*)malloc(sizeof(node));
	(*list)->next = (*list);
	(*list)->prior = (*list);
	node *p = (*list);
	node *r;
	while (n > 0)
	{
		/*类似插入,也是有3个节点*/
		node *temp = (node*)malloc(sizeof(node));
		temp->data = n;
		r = p->next;

		p->next = temp;
		temp->prior = p;

		temp->next = r;
		r->prior = temp;

		n--;
	}
}

void lprint(linklist l)
{
	node *p;
	p = l->next;
	while (p != l)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

int main()
{
	int a;
	linklist list=NULL;
	creat(&list, 3);
	lprint(list);
	linsert(list,2,7);
	lprint(list);
	ldelete(list,3,&a);
	lprint(list);
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值