线性表介绍

线性表是一种常用的数据结构。在实际应用中,线性表都是以栈、队列、字符串、数组等特殊线性表的形式来使用的。由于这些特殊线性表都具有各自的特性,因此,掌握这些特殊线性表的特性,对于数据运算的可靠性和提高操作效率都是至关重要的。 

线性表是一个线性结构,它是一个含有n≥0个结点的有限序列,对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点,有且仅有一个终端结点没有后继但有一个前驱结点,其它的结点都有且仅有一个前驱和一个后继结点

线性表分为顺序存储和链式存储。

这里主要简单介绍一下顺序存储,其特点是可以随机地访问元素,缺点是在进行插入和删除操作时需要移动大量的元素。

C语言实现代码:

/*
Introduction:easy data structure of list
Date:2017-03-26 
*/ 

#include <stdio.h>  
#include <stdlib.h>  
//宏定义  
#define TRUE   1  
#define FALSE   0  
#define OK    1  
#define ERROR   0  
#define INFEASIBLE -1  //infeasible意为不可执行的 
#define OVERFLOW -2   //代表溢出       

#define LIST_INIT_SIZE 100 //线性表初始空间分配量  
#define LISTINCREMENT   10 //线性表空间分配的增量  

typedef int Status;  
typedef int ElemType;  

typedef struct LNode{  
    ElemType  *elem;        //存储空间的基地址  
    int      length;        //当前的长度  
    int      listsize;      //当前分配的存储容量  
}SqList;  

/** 
 *构造空的线性表 
 */  

Status initList(SqList &L, int size){  
    if (size == 0) size = LIST_INIT_SIZE;  
    L.elem = (ElemType *)malloc(size * sizeof(ElemType));  
    if(!L.elem) exit(OVERFLOW);  //分配存储空间失败  
    L.length = 0;                //初始空表长度为0  
    L.listsize = size ;//初始存储容量为100  
    return OK;  
}  
/************************************************************************/  
/* 在第i位置插入e 
*/  
/************************************************************************/  
Status insertList(SqList &L, ElemType e, int i){  
    ElemType *p,  *q;  
    if(i<0 ||i > L.length) return ERROR;  //i值不合法  
    if (L.length >= L.listsize) {  
        ElemType *newbase = (ElemType *)realloc(L.elem ,(L.listsize +LISTINCREMENT)*sizeof(ElemType));  
        if(!newbase) return OVERFLOW;   //存储分配失败    
        L.elem = newbase;               //新基值  
        L.listsize += LISTINCREMENT;    //增加存储容量  
    }  
    q = &L.elem[i];                     //q为插入的位置  
    for (p = &L.elem[L.length]; p>=q; --p) {  
        *p = *(p-1);                    //i元素之后的元素往后移动  
    }  
    *q = e;                             //插入e  
    L.length +=1;  
    return OK;  

}  
/************************************************************************/  
/* 删除第i位置元素,并用e返回其值                                                                     */  
/************************************************************************/  
Status deleteListElem(SqList &L, int i, ElemType &e){  
    int *p,  *q;  
    if(i<0 ||i > L.length) return ERROR;  //i值不合法  
    q = &L.elem[i];                       //被删除元素的位置为i,L.elem就是数组名,  
    e = *q;                               //被删除元素的值赋值给e  
    for (p = q; p< (L.elem + L.length); p++){ //元素左移  
        *p = *(p+1);  
    }  
    --L.length;  
    return OK;  
}  

/************************************************************************/  
/*  快速排序 
*/  
/************************************************************************/  

int partition(SqList &L, ElemType low, ElemType high){  
    ElemType pivotkey = L.elem[low];               //枢轴记录关键字  
    while (low < high) {                  //从表的两端向中间扫描  
        while (low < high &&  L.elem[high] >= pivotkey ) --high;//高端位置扫描  
        L.elem[low] = L.elem[high];     //交换数据,小于pivotkey移到低端  
        L.elem[high] = pivotkey;  

        while (low < high && L.elem[low] <= pivotkey ) ++low;     //低端扫描  
        L.elem[high] = L.elem[low];               //交换数据 大于pivotkey移到高端  
        L.elem[low] = pivotkey;                                   
    }  
    return low;  
}  

void quickSort(SqList &L, ElemType low, ElemType high){  
    int pivot;  
    if(low < high) {                                          
        pivot =  partition(L,  low,  high);       
        quickSort(L,  low,  pivot -1);          //低端子表排序  
        quickSort(L,  pivot +1, high);          //高端子表排序  
    }  

}  


/************************************************************************/  
/*  
合并两个线性表 
*/  
/************************************************************************/  

void mergeList(SqList La, SqList Lb,  SqList &Lc){  
    ElemType *pa, *pb, *pc;  
    Lc.listsize =  La.length + Lb.length;  
    initList(Lc, Lc.listsize);          //初始化LC\pc = Lc.elem;  
    Lc.length = Lc.listsize;  
    pc = Lc.elem;  
    pa = La.elem;  
    pb = Lb.elem;  
    while (pa <= &La.elem[La.length -1] && pb <= &Lb.elem[Lb.length -1]){  
        if (*pa <= *pb) *pc++ = *pa++;  
        else *pc++ = *pb++;  
    }  
    while(pa <= &La.elem[La.length -1]) *pc++ = *pa++; //插入La的剩余元素  
    while(pb <= &Lb.elem[Lb.length -1]) *pc++ = *pb++; //插入Lb的剩余元素  

}  

/************************************************************************/  
/* 打印list 
*/  
/************************************************************************/  
void printList(SqList L){  
    printf("当前值:");   
    for (int i =0; i<L.length;i++) {  
        printf("%d ", *(L.elem+i)); // L.elem为首地址  
    }   
    printf("\n");   
}  

int main()  
{  
    SqList La,Lb,Lc;  
    ElemType e;  
    int init,i;  
    init = initList(La, LIST_INIT_SIZE);  
    int data[6] = {5,3,6,2,7,4};  
    for (i=0; i<6;i++) {  
        insertList(La,  data[i],  i);  
    }  
    printf("LA:\n");   
    printList(La);  
    //测试删除 
    deleteListElem(La, 3, e );  
    printList(La); 
    //测试插入 
    insertList(La,  e,  3);  
    printList(La);  

    //实现快速排序并将结果打印 
    quickSort(La,0, La.length-1);  
    printList(La);  

    printf("LB:\n");   
    initList(Lb, LIST_INIT_SIZE);  
    int Bdata[5] = {1,3,2,4,6};  
    for (i=0; i<5;i++) {  
        insertList(Lb,  Bdata[i],  i);  
    }  
    //实现快速排序并将结果打印  
    quickSort(Lb,0, Lb.length-1);  
    printList(Lb);  

    //测试合并 
    mergeList(La, Lb,  Lc);  
    printf("合并之后:\n");
    printList(Lc);  

    return 0;  
} 

在定义线性表时,我们可以定义一个结构体来标识线性表

typedef struct LNode{  
    ElemType  *elem;        //存储空间的基地址  
    int      length;        //当前的长度  
    int      listsize;      //当前分配的存储容量  
}SqList;  

其中,我们必须定义线性表第一个元素的存放位置,即整个线性表的首地址,还要定义线性表的最大容量listsize,最后用一个length来表示当前线性表中元素的数目即线性表的长度


再接着我们介绍一下线性表的链式存储,这样的优点是插入和删除元素时只要改变指针的指向即可,缺点是要访问一个元素时必须进行遍历,不能确切地知道元素的位置。

C语言实现代码:

/*
Introduction:easy Data Structure of LinkList
Date:2017-03-26 
*/ 
#include <stdio.h>  
#include "stdlib.h"  

#define TRUE   1  
#define FALSE   0  
#define OK    1  
#define ERROR   0  
#define OVERFLOW -2  

typedef int Status;  
typedef int ElemType;  

typedef struct LNode{   
    ElemType  data;     //数据域          
    struct LNode   *next;  //指向下一个元素的指针域   
}LNode, *LinkList;  

/************************************************************************/  
/* 
初始化链表 
*/  
/************************************************************************/  
Status initList(LinkList &L){  
    /*单链表的初始化*/  
    L = (LinkList)malloc(sizeof(LNode));    //申请一个头节点  
    if(!L) exit(OVERFLOW);          //申请空间失败    
    L->next=NULL;                //建立一个带头节点的空链表  
    return OK;  
}  

/************************************************************************/  
/*      
创建链表 
*/  
/************************************************************************/  
void createList(LinkList L, int n){  
    /*单链表的初始化*/  
    if (!L) {  
        initList(L);  
    }  
    ElemType data;  
    LinkList p,q = L;  
    printf("输入节点数据的个数%d:\n", n);  
    for(int i = 0; i<n; i++) {   
        scanf("%d",&data); 
        p = (LinkList) malloc( sizeof(LNode)); //申请一个新节点  
        q->data = data;  
        q->next=p;
        if(i==n-1){     //当到了最后的一个节点时一定要将其next指针置为NULL 
           q->next=NULL;break;  
        }
        q=p;
    }  
}  
/************************************************************************/  
/* 在第i位置插入e 
*/  
/************************************************************************/  
Status insertList(LinkList L, ElemType e, int i){  
    LinkList s, p = L;  
    int j = 0;  
    while (p && j<i){                //寻找i节点  
        p = p->next;  
        j++;  
    }  
    if (!p ||j >i) return ERROR;  
    s = (LinkList) malloc(sizeof(LNode));       //生成新节点  
    s->data = e; s->next = p->next;            //插入L中  
    p->next = s;  
    return OK;  

}  

/************************************************************************/  
/* 删除第i位置元素,并用e返回其值                   */  
/************************************************************************/  
Status deleteListElem(LinkList L, int i, ElemType *e){  
    LinkList p, q;
    int j = 0;  
    p = L;  
    while (p && j<i){  
        p = p->next;  
        ++j;  
    }  
    if (!p->next || j>i)  return ERROR;   //删除的位置不对  
    q  = p->next; p->next = q->next;  
    *e = q->data; free(q);            //释放节点  
    return OK;  
}  


/************************************************************************/    
/*  插入排序  
*/    
/************************************************************************/    
 /* 

1、先在原链表中以第一个节点为一个有序链表,其余节点为待定节点。 
2、从图12链表中取节点,到图11链表中定位插入。 
3、上面图示虽说画了两条链表,其实只有一条链表。在排序中,实质只增加了一个用于指向剩下需要排序节点的头指针first罢了。 
   这一点请读者务必搞清楚,要不然就可能认为它和上面的选择排序法一样了。 
*/  
LinkList InsertSort(LinkList L)  
{  
    LinkList first; /*为原链表剩下用于直接插入排序的节点头指针*/  
    LinkList t; /*临时指针变量:插入节点*/  
    LinkList p; /*临时指针变量*/  
    LinkList q; /*临时指针变量*/  

    first = L->next; /*原链表剩下用于直接插入排序的节点链表:可根据图12来理解。*/  
    L->next = NULL; /*只含有一个节点的链表的有序链表:可根据图11来理解。*/  
    while (first != NULL) /*遍历剩下无序的链表*/  
    {  
        /*注意:这里for语句就是体现直接插入排序思想的地方*/  
        for (t = first, q = L;q != NULL && q->data < t->data;p = q, q = q->next);
         /*无序节点在有序链表中找插入的位置*/  

    /*退出for循环,就是找到了插入的位置*/  
    /*注意:按道理来说,这句话可以放到下面注释了的那个位置也应该对的,但是就是不能。原因:你若理解了上面的第3条,就知道了。*/  
        first = first->next; /*无序链表中的节点离开,以便它插入到有序链表中。*/   

        if (q == L) /*插在第一个节点之前*/  
        {  
            L = t;  
        }  
        else /*p是q的前驱*/  
        {  
            p->next = t;  
        }  
        t->next = q; /*完成插入动作*/  
        /*first = first->next;*/  
    } 
    return L;
}  
/************************************************************************/  
/*  
合并两个线性表 
*/  
/************************************************************************/  

LinkList mergeList(LinkList  &La, LinkList  &Lb,  LinkList &Lc){ 
    LinkList Test;
    Test=La;
    while(La->next!=NULL){
        La=La->next;
    }  //先遍历链表La,使La的尾节点的指针指向Lb的头节点 
    La->next=Lb;
    Lc=Test;
    Lc=InsertSort(Lc);
    return Lc; 
}  

/************************************************************************/  
/* 打印list 
*/  
/************************************************************************/  
void printList(LinkList  L){  
    printf("打印链表:");  
    LinkList p;  
    p = L;  
    while(p){  
        printf("%d ", p->data);   
        p = p->next;  
    }  
    printf("\n");   
}  

int main()  
{  
    LinkList  La,Lb,Lc;  
    ElemType *e;  
    int init,i;  
    printf("La:\n");    
    initList(La);  
    createList(La, 5);
    printf("创建La之后的各元素值:\n");
    printList(La);  
    insertList(La, 7,  3); 
    printf("插入元素之后的各元素值:\n");   
    printList(La);  
    deleteListElem(La, 3,  e); 
    printf("删除的元素为:%d\n",*e);
    printf("删除元素之后的各元素值:\n");   
    printList(La);

    //输出插入排序之后的表 
    La=InsertSort(La);
    printf("插入排序之后La的各元素值:\n"); 
    printList(La);  

    printf("\n\n");

    printf("Lb:\n");    
    initList(Lb);  
    createList(Lb, 4); 
    printf("创建Lb之后的");
    printList(Lb);

    //输出插入排序之后的表 
    Lb=InsertSort(Lb);
    printf("插入排序之后Lb的各元素值:\n");
    printList(Lb);  

    printf("\n\n");

    printf("Lc:\n");   
    initList(Lc); //初始化一个空表 
    Lc=mergeList(La,Lb,Lc);  
    printf("合并之后的表:\n");
    printList(Lc);  

    return 0;
}

这里主要需要弄清楚插入排序的思想和链式存储指针域的指向问题。


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值