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

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

posted on 2017-12-06 19:47  一只想做高手的小羊  阅读(241)  评论(0)    收藏  举报

导航