数据结构之链表

一、定义--离散存储【链表】

n个节点离散分配;彼此通过指针相连;每个节点只有一个前驱节点,
每个节点只有一个后续节点;首节点没有前驱节点,尾节点没有后续节点。

二、专业术语:

首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:第一个有效节点前面的那个节点;头节点不存放有效数据;
加上头节点是为了方便对链表的操作
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量

三、分类:单链表;双链表;循环链表;非循环链表

四、代码

#include<stdio.h> 
#include<malloc.h> 
#include<stdlib.h> 

typedef struct node{
    int data; //数据域 
    struct node * pNext; //指针域 
}NODE,* PNODE;  //NODE等价于struct node;PNODE等价于 struct node * 

PNODE init_link(void);
void traverse_link(PNODE pHead);
bool is_empty(PNODE pHead);
int length_link(PNODE pHead);
bool insert_link(PNODE pHead,int pos,int val);
bool del_link(PNODE pHead,int pos,int * val);
bool sort_link(PNODE pHead);

int main(void)
{
    //首先创建头节点
    PNODE pHead = NULL;  //一个指针只需一个参数,即头节点即可确定下来。 
    int val;
    int * pVal = &val;  //用来接收删除的节点数据 
    
    pHead = init_link();
    
    if(is_empty(pHead))
    {
        printf("数组为空。。。\n");
    }else{
        
        printf("数组不为空。。。\n");
    }
    printf("数组长度为:%d\n",length_link(pHead)); 
    
    traverse_link(pHead);
    
    insert_link(pHead,3,333);
    traverse_link(pHead);
    
    if(del_link(pHead,4,pVal))
    {
        printf("链表节点删除成功,你删除的节点数据是:%d 。\n",*pVal);
    }else{
        printf("链表节点删除失败!");
    }

    
    
    sort_link(pHead);
    traverse_link(pHead);
    
    
     
    return 0;
}

PNODE init_link(void)
{
    int i;
    int len;  //链表有效长度 
    int val;  //临时存放用户数据 
    
    printf("请输入链表有效长度:len= ");
    scanf("%d",&len);
    
    PNODE pHead = (PNODE)malloc(sizeof(NODE));
    if(pHead == NULL)
    {
        printf("内存分配失败,程序终止\n");
        exit(-1);
    }
    PNODE pTail = pHead;  //设置一个尾指针,永远指向尾节点,方便新节点pNew挂在后面 
    pTail->pNext = NULL;
    
     
    
    for(i=0;i<len;i++)
    {
        printf("请输入第 %d 个节点的值:",i+1);
        scanf("%d",&val);
        
        PNODE pNew = (PNODE)malloc(sizeof(NODE));
        if(pNew == NULL)
        {
            printf("内存分配失败,程序终止\n");
            exit(-1);
        }
        
        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }
    return pHead;
    
}
void traverse_link(PNODE pHead)
{
    PNODE p = pHead->pNext;  //第一个有效节点 
    while(p!=NULL)
    {
        printf("%d  ",p->data);
        p = p->pNext; 
        
    }
    printf("\n");
}

bool is_empty(PNODE pHead)
{
    PNODE p = pHead->pNext;
    if(p==NULL)
        return true;
    else
        return false;
} 

int length_link(PNODE pHead)
{
    int cnt=0;
    PNODE p = pHead->pNext;
    while(p!=NULL)
    {
        cnt++;
        p = p->pNext;
    }
    return cnt;
}
bool insert_link(PNODE pHead,int pos,int val)
{
    int i=0;
    PNODE p = pHead;
    
    while(p!=NULL && i<pos-1)
    {
        p = p->pNext;
        i++;
    }
    if(p==NULL || i>pos-1)
        return false;
    PNODE pNew = (PNODE)malloc(sizeof(NODE));
    if(pNew==NULL)
    {
        printf("动态内存分配失败!\n");
        exit(-1);
    } 
    pNew->data = val;
    PNODE q = p->pNext;
    p->pNext = pNew;
    pNew->pNext = q;
    return true; 
}
bool del_link(PNODE pHead,int pos,int * pVal)
{
    int i=0;
    PNODE p = pHead;
    
    while(p->pNext!=NULL && i<pos-1)
    {
        p = p->pNext;
        i++;
    }  //经过while循环,p此时指向pos位置前面那个节点 
    if(p->pNext==NULL || i>pos-1)
        return false;
    
    PNODE q = p->pNext; //q即为pos位置处的节点 
    *pVal = q->data;
    //删除pos位置的节点 
    p->pNext = p->pNext->pNext;
    free(q);  //释放内存,防止内存泄漏。 
    q = NULL;
    return true;
}

/*
何为算法:
        狭义的算法是与数据的存储方式密切相关的;
        广义的算法是与数据的存储方式无关的;
    泛型:
        利用某种技术达到的效果就是:针对不同的存储方式,执行的操作是一样的
*/
bool sort_link(PNODE pHead)
{
    int i,j,temp;  //数组中定义的参量 
    PNODE p,q;  //链表中定义的参量 
    
    for(i=0,p = pHead->pNext;i<length_link(pHead)-1;i++,p=p->pNext)
        for(j=i+1,q=p->pNext;j<length_link(pHead);j++,q=q->pNext)
            if(p->data<q->data)         //等价于a[i]<a[j]
            {
                temp = q->data;        //等价于a[i] = a[j];
                q->data = p->data;    //a[j] = a[i];
                p->data = temp;        //a[i] = temp;
            }
    
}

运行结果:

五、数组与链表优缺点对比

数组(元素类型相同,大小相等):
优点:存取速度很快;
缺点:插入删除速度很慢;空间通常有限制;事先需要知道数组长度;需要大块内存块

链表:

优点;空间没有限制;插入删除元素很快
缺点:存取速度慢

posted @ 2018-08-20 18:34  刘建东  阅读(268)  评论(0编辑  收藏  举报