线性表之离散存储(链表)

1.什么是链表?

  链表和数组都是线性表的分支.逻辑上他们都是相连的。但是在物理上面链表和数组相反,链表具有以下四个性质:

    (1)n个节点离散分配
    (2)节点彼此通过指针相连
    (3)每一个节点只有一个前驱节点和一个后驱节点
    (4)首节点没有前驱节点 尾节点没有后续节点


2.链表的专业术语?

  首节点:第一个有效节点(要有数据域和指针域)
  尾节点:最后一个有效节点
  头结点:第一个有效节点之前的那个节点
      头结点并不存放有效数据(数据域)
      它只有指针域,指向首节点
      加头结点就是为了方便对链表的操作
  头指针:指向头结点的指针变量
  尾指针:指向尾节点的指针变量

  注意:和数组一样,我们确定一个数组只需要知道首节点的地址,数组的有效长度,数据最大长度.那么确定一个链表需要几个参数呢?
    答:只需要一个参数,头指针,知道头指针可以很快知道下面各个节点的信息

3.链表的分类
  链表可以分为四类:
    单链表:只有一个指针域,它是指向下一个节点
    双链表:一个节点有两个指针域,分别指向前后两个节点元素
    循环链表:节点与节点之间形成一个环状,可以找到任意一个节点
    非循环链表:就是普通的链表(可双可单)


4.链表的算法操作

  PNODE createNodeList(int len);//初始化链表(给链表分配len个长度的内存空间)
  void showNodeList(PNODE pHead);//显示链表的基本信息
  bool is_empty(PNODE pHead);//判断链表是否为空
  int NodeList_Length(PNODE pHead);//获得链表的长度
  bool insert_NodeList(PNODE pHead,int pos,int val);//在链表指定位置(pos>=1)插入值(val)
  bool delete_NodeList(PNODE pHead,int pos);//删除指定位置的数值
  bool update_NodeList(PNODE pHead,int pos,int val);//更改指定位置的数值为val
  NODE get(PNODE pHead,int pos);//获得指定位置的数值
  void sort_NodeList(PNODE pHead);//升序排序

  1)初始化链表,先要动态分配len个长度的内存空间给头指针(pHead),然后判断空间是否分配正确,如果正确的话,那么这个头指针也代表尾指针(因为开始只有一个节点)。接着每循环一次创建一个新的节点(pNew),将其挂在尾指针(pTail)后面,如此一来,链表初始化完毕.

//初始化链表
PNODE createNodeList(int len){
	PNODE pTail;
	int i,val; 
	PNODE pHead = (PNODE)malloc(sizeof(NODE)*len);//动态分类len个长度空间
	if(pHead==NULL){
		printf("链表空间分配失败,退出程序!");
		exit(-1); 
	}
	pTail = pHead;
	pTail->pNext=NULL;
	for(i=0;i<len;i++){
		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		printf("请输入第%d个元素的值:",i+1);
		scanf("%d",&val);
		pNew->data=val;
		pTail->pNext=pNew;
		pNew->pNext=NULL;
		pTail=pNew;
	}
	return pHead;
}
2)输出链表的基本信息,是通过while循环来判断的,只要是p->pNext不为空,那么就说明整个链表有节点存在,便输出p->data.

//输出链表的值
void showNodeList(PNODE pHead){
	PNODE p = pHead->pNext;
	int num = NodeList_Length(pHead);
	if(num!=0){
		printf("链表的长度为%d,分别为",num);
		while(p!=NULL){
		printf("%d ",p->data);
		p=p->pNext;
		}
		printf("\n");
	}

} 
3)判断链表是否为空,比较简单,只需要判断头指针pHead->pNext是否为空,也就是头指针后面是否有节点就可以了.

//判断链表为不为空
bool is_empty(PNODE pHead){
	PNODE p = pHead->pNext;
	if(p==NULL)
		return true;
	return false;
}
4)获得链表的长度,先定义一个中间变量num,然后通过while循环判断p->pNext是否为空,不为空就加一,直到不满足循环条件就说明链表已经到头了,长度因此获得.

int NodeList_Length(PNODE pHead){
	int num=0;
	PNODE p = pHead->pNext;
	if(is_empty(pHead))
		return 0;
	while(p!=NULL){
		num++;
		p=p->pNext;
	}
	return num;
}
5)往链表指定位置插入一个数值,这个算法相对而言比较麻烦。因为链表不像数组那样,可以很快的定位插入的位置,所以链表的插入算法首先要找到插入位置的前一个节点,然后自己要新建一个pNew新节点用来存放想要插入的值,接着将pNew与前一个节点相互连接,pNew与插入位置后一个节点再连接一下,表示插入成功.基本思想就是这样.

//往链表中插入一个元素 
bool insert_NodeList(PNODE pHead,int pos,int val){
	PNODE p = pHead->pNext;
	PNODE pNew,pTemp;
	int i=1;
	if(pos<1||pos>NodeList_Length(pHead)+1)
		return false;
	//1 2 34 4 5 6 7    :pos=6
	while(p!=NULL&&i<pos-1){
		i++;
		p=p->pNext;//p已经是第五个节点了 
	}
	pNew=(PNODE)malloc(sizeof(NODE));
	pTemp = p->pNext;
	pNew->data=val;
	p->pNext=pNew;
	pNew->pNext=pTemp;
	return true;
}
6)链表的删除节点算法

bool delete_NodeList(PNODE pHead,int pos){
	int i=1;
	PNODE pTemp;
	PNODE p = pHead->pNext;

	if(p==NULL){
		printf("链表为空,无法继续删除,退出程序!");
		return false;
	}
	// 1 2 3 4 5 6  pos=3;
	while(p!=NULL&&i<pos-1){
		i++;
		p=p->pNext;  //此时的p是要删除的数的前一个 
	}
	pTemp = p->pNext;
	p->pNext = p->pNext->pNext;
	free(pTemp);
	return true;
}
7)链表的更改节点算法

bool update_NodeList(PNODE pHead,int pos,int val){
	int i=1;
	PNODE p =pHead->pNext;
	if(p==NULL){
		printf("链表为空,无法修改,退出程序!");
		return false;
	}
	while(p!=NULL&&i<pos){
		i++;
		p=p->pNext;
	}
	p->data=val;
	return true;
}
8)获取指定位置的数据(返回节点元素)

NODE get(PNODE pHead,int pos){
	PNODE p = pHead->pNext;
	int i=1;
	while(p!=NULL&&i<pos){
		i++;
		p=p->pNext;
	}
	return *p;
}
9)链表排序算法

void sort_NodeList(PNODE pHead){
		PNODE p,q;
		int i,j;
		int length= NodeList_Length(pHead);
		for(i=0,p=pHead->pNext;i<length-1;i++,p=p->pNext){
			for(j=i+1,q=p->pNext;j<length;j++,q=q->pNext){
				if(p->data>q->data){
					int temp=p->data;
					p->data=q->data;
					q->data=temp;
				}
			}
		}
}


总结:个人感觉链表算法还是很重要的,因为后面的队列,栈,树都要用到链表,所以链表既是重点又是难点.(这几天一直很忙,更新有点慢,下一篇就是栈和队列)

链表源码下载地址:http://download.csdn.net/download/qq_31308883/10148594

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值