zoukankan      html  css  js  c++  java
  • 数据结构——线性表

    一、线性表的抽象数据类型

    ADT 线性表(List)

    Data

      线性表的数据对象集合为{a1, a2, … , an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。

    Operation

      InitList(*L):初始化操作,建立一个空的线性表L。

      ListEmpty(L):若线性表为空,返回true,否则返回false。

      ClearList(*L):将线性表清空。

      GetElem(L,i,*e):将线性表L的第i个位置元素返回给e。

      LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号以表示成功,否则返回0表示失败。

      ListInsert(*L,i,e):在线性表L中的第i个位置(前)插入新元素e。

      ListDelete(*L,i,*e):删除线性表L中第i个位置元素,并用e返回其值。

      ListLength(L):返回线性表L的元素个数。

      ListTraverse(L):遍历线性表并打印。

    endADT

     ==========================2017-9-27补充=================================

    问题描述:之前看到这个ADT中的各个操作时,对于调用的形参很是困惑——为什么有些就是传地址,而有些就是传值啊?

    问题解决:

      传值:被调用函数不能修改此形参的值,只能使用它来作为一个“数字”(用来引用)。

      传地址:被调用函数可以修改此形参的值(因为传地址就是传指针,所以可以修改指针指向的内容)。

      所以,若我们想改变形参的值时,就需要传地址;而只是引用形参的值时,就可以传值了(传指针好像也没什么错,不过为了防止不小心改变形参值,还是选传值较为妥当)。

    =============================补充结束===================================

    二、必要概念

    结点(Node):线性表中是这个“结点”,而不是那个“节点”。

    线性表的链接存储结构:n个结点 链结 成一个链表,即为线性表(a1,a2,…,an)的链式存储结构。

    单链表:当链表的每个结点中只包含一个指针域时。

    头指针:链表中的第一个结点的存储位置。(因为指针就是地址啊!)

    头结点:在单链表的第一个结点前附设的结点。(头结点的数据域可不存储任何信息,也可以存储如线性表的长度等附加信息;而指针域存储指向第一个结点的指针!)

    头结点&头指针:头指针是指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。若线性表为空表,则头结点的指针域为“空”,但是头指针仍指向头结点。

    三、线性表的链接存储

    1. 单链表的创建

    创造单链表的过程就是一个动态生成链表的过程。即从“空表”的初始状态起,依次建立各元素结点,并逐个插入链表。

    头插法算法思路为:

    1. 声明一指针p;
    2. 初始化一空链表L;
    3. 让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
    4. 循环:生成一新结点赋值给p;随机生成一数字赋值给p的数据域p->data;将p插入到头结点与前一新结点之间。

    【头插法】

    在这种方法中,新结点始终是第一个结点(位于头结点之后)。

     1 /*    随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)    */
     2 void CreateListHead(List *L, int n)
     3 {
     4     List p;
     5     srand(time(0));                            //初始化随机数种子 
     6     *L = (List)malloc(sizeof(Node));
     7     (*L)->next = NULL;                        //先建立一个带表头结点的单链表 
     8     for(int i=0; i<n; i++){
     9         p = (List)malloc(sizeof(Node));        //生成新结点 
    10         p->data = rand()%100+1;                //随机生成100以内的数字 
    11         p->next = (*L)->next;
    12         *(L)->next = p;                        //插入到表头 
    13     }
    14 } 
    View Code

    【尾插法】

    这才是正常的思维,新结点总是放在表的最后。

     1 /*    随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法)    */
     2 //L是指整个单链表,而r是指向尾结点的变量
     3 //r会随着循环不断地变化结点,而L则是随着循环增长为一个多结点的链表 
     4 void CreateListTail(List *L, int n)
     5 {
     6     List p, r;
     7     srand(time(0));                            //初始化随机数种子 
     8     *L = (List)malloc(sizeof(Node));        //为整个线性表 
     9     r = *L;                                    //r为指向尾部的结点 
    10     for(int i=0; i<n; i++){
    11         p = (List)malloc(sizeof(Node));        //生成新结点 
    12         p->data = rand()%100+1;                //随机生成100以内的数字 
    13         r->next = p;                        //将表尾终端结点的指针指向新结点 
    14         r = p;                                //将当前的新结点定义为表尾终端结点 
    15     }
    16     r->next = NULL;                            //表示当前链表结束 
    17 }
    View Code

    2. 完整代码

    /*	线性表的顺序存储	*/
    //线性表的序号从1开始 
    #include <cstdio>
    #include <ctime>
    #include <malloc.h>
    
    typedef int ElemType;
    
    typedef struct node{
    	ElemType data;
    	struct node * next;
    }Node;
    
    typedef Node * List;
    
    /*	将线性表L的第i个位置元素返回给e	*/
    bool GetElem(List L, int i, ElemType *e)
    {
    	List p;
    	p = L->next;	//让p指向链表L的第一个结点 
    	int pos = 1;
    	while(p && pos < i){
    		p = p->next;
    		pos++;
    	} 
    	if(!p || pos > i)	//第i个结点不存在  
    		return false;
    	*e = p->data;
    	return true;
    } 
    
    /*	在线性表L中的第i个位置(前)插入新元素e	*/
    bool ListInsert(List *L, int i, ElemType e)
    {
    	List p, s;
    	p = *L;		//L是二重指针
    	int pos = 1;
    	while(p && pos < i){
    		p = p->next;
    		pos++;
    	}
    	if(!p || pos>i)
    		return false;
    	s = (List)malloc(sizeof(Node));
    	s->data = e;
    	s->next = p->next;
    	p->next = s;
    	return true;
    } 
    
    /*	删除线性表L中第i个位置元素,并用e返回其值	*/
    bool ListDelete(List *L, int i, ElemType *e)
    {
    	List p, q;
    	p = *L;
    	int pos = 1;
    	while(p->next && pos < i){
    		p = p->next;
    		pos++;
    	}
    	if(!(p->next) || pos > i)
    		return false;
    	*e = q->data;
    	q = p->next;
    	p->next = q->next;
    	free(q);		//释放内存 
    	return true;
    }
    
    /*	随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)	*/
    /*
    void CreateListHead(List *L, int n)
    {
    	List p;
    	srand(time(0));							//初始化随机数种子 
    	*L = (List)malloc(sizeof(Node));
    	(*L)->next = NULL;						//先建立一个带表头结点的单链表 
    	for(int i=0; i<n; i++){
    		p = (List)malloc(sizeof(Node));		//生成新结点 
    		p->data = rand()%100+1;				//随机生成100以内的数字 
    		p->next = (*L)->next;
    		*(L)->next = p;						//插入到表头 
    	}
    }
    */
    
    /*	随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法)	*/
    //L是指整个单链表,而r是指向尾结点的变量
    //r会随着循环不断地变化结点,而L则是随着循环增长为一个多结点的链表 
    void CreateListTail(List *L, int n)
    {
    	List p, r;
    	srand(time(0));							//初始化随机数种子 
    	*L = (List)malloc(sizeof(Node));		//为整个线性表 
    	r = *L;									//r为指向尾部的结点 
    	for(int i=0; i<n; i++){
    		p = (List)malloc(sizeof(Node));		//生成新结点 
    		p->data = rand()%100+1;				//随机生成100以内的数字 
    		r->next = p;						//将表尾终端结点的指针指向新结点 
    		r = p;								//将当前的新结点定义为表尾终端结点 
    	}
    	r->next = NULL;							//表示当前链表结束 
    }
    
    /*	将单链表清空	*/
    void ClearList(List *L)
    {
    	List p, q;
    	p = (*L)->next;				//p指向第一个结点 
    	while(p){					//没到表尾 
    		q = p->next;
    		free(p);
    		p = q;
    	}
    	(*L)->next = NULL;			//头结点指针域为空 
    }
    
    int ListLength(List L){
        int cnt = 0; 		//计数器
        while(L->next){
            L = L->next;
            cnt++;
        } 
        return cnt;
    } 
    
    /*	遍历单链表并打印	*/ 
    void ListTraverse(List L){
        if(L->next == NULL){
            printf("链表为空!");
        }else{
            List p;
            p = L->next;
            while(p != NULL){
                printf("%d ",p->data);
                p = p->next;
            }
            printf("
    ");   
        }
    }
    
    void read()
    {
    	List L;
    	CreateListTail(&L,10);
    	printf("初始化10个元素,分别是: 
    "); 
        ListTraverse(L);
        ElemType e; 
        GetElem(L, 4, &e);
        printf("链表中第4个元素是: %d 
    ",e); 
        printf("链表的长度是: %d 
    ",ListLength(L));
        ListInsert(&L, 4, 12);
        printf("在链表第4个元素之前插入12 
    "); 
        ListTraverse(L);
        ListDelete(&L, 5, &e);
        printf("在链表中删除第5个元素 
    "); 
        ListTraverse(L);
        ClearList(&L);
        printf("清除链表之后的元素: 
    "); 
        ListTraverse(L);
    }
    
    int main()
    {
    	read();
    	return 0;
    } 
    

    三、线性表的顺序存储

    1. 完整代码

      1 /*线性表功能的实现*/
      2 #include<stdio.h>
      3 
      4 //定义常量 存储空间的初始化分配
      5 #define MAXSIZE 20
      6 #define TRUE 1
      7 #define ERROR -1
      8 #define FALSE 0
      9 #define OK 1
     10 
     11 //用typedef定义类型
     12 typedef int Status;
     13 typedef int ElemType;
     14 //定义一个结构体类型
     15 typedef struct{
     16     ElemType data[MAXSIZE];
     17     int length;
     18 } SqList; 
     19 
     20 //初始化函数
     21 Status initList(SqList *L){
     22     L->length = 0;
     23     return OK; 
     24 } 
     25 
     26 //返回线性表的长度
     27 Status getListLength(SqList L){
     28     return L.length;
     29 }
     30 
     31 //线性表为空返回true,否则返回false
     32 Status listEmpty(SqList L){
     33     if(L.length == 0){
     34         return TRUE; 
     35     }
     36     return FALSE;
     37 } 
     38 
     39 //线性表清空,长度为0 
     40 Status clearList(SqList *L){
     41     L->length = 0; 
     42     return OK;
     43 } 
     44 //获取指定的元素的值,返回下标为i - 1的元素,赋值给e
     45 Status getElem(SqList L, int i, ElemType *e){
     46     //判断元素位置是否合法[i]
     47     if(i > L.length || i < 1){
     48         printf("查找的位置不正确 
    ");
     49         return ERROR; 
     50     }
     51     //判断线性表是否为空
     52     if(listEmpty(L)){
     53         return ERROR;
     54     } 
     55     *e = L.data[i - 1];
     56     return OK;
     57 }
     58 
     59 //在线性表中查找指定的e相等的元素,如果查找成功,返回该元素的下标,否则返回ERROR
     60 Status locateElem(SqList L, ElemType e){
     61     int i;
     62     for(i = 0; i < L.length - 1; i++){
     63         if(L.data[i] == e){
     64             return i;
     65         }
     66     }
     67     printf("没有查找到元素 %d 指定的下标
    ",e);
     68     return ERROR;
     69 } 
     70 
     71 //自动创建 MAXSIZE 个元素,并赋值为0 
     72 Status createList(SqList *L){
     73     int i;
     74     for(i = 0; i < 10; i++){
     75         L->data[i] = 0;
     76     } 
     77     L->length = 10;
     78     return OK;
     79 } 
     80 
     81 //在线性表中第i个位置前插入新元素e 
     82 Status listInsert(SqList *L, int i, ElemType e){
     83     //判断长度是否可以允许插入新的数据 
     84     if(L->length >= MAXSIZE){
     85         printf("空间已满,不能再插入数据
    ");
     86         return FALSE; 
     87     }
     88     //判断插入位置的合法性
     89     if(i < 1 || i > L->length) {
     90         printf("插入位置不正确
    ");
     91         return FALSE;
     92     }
     93     int j;
     94     for(j = L->length - 1; j >= i; j--){
     95         L->data[j] = L->data[j - 1];
     96     }
     97     L->data[i - 1] = e;
     98     L->length++;
     99     return TRUE;
    100 }
    101 
    102 //删除线性表中第i个元素,成功后表长减1,用e返回其值 
    103 Status deleteList(SqList *L, int i, ElemType *e){
    104     //判断线性表是否为空
    105     if(listEmpty(*L)){
    106         return ERROR;
    107     }
    108     //判断删除的位置是否合法
    109     if(i < 1 || i > L->length) {
    110         printf("删除位置不合法
    ");
    111         return ERROR;
    112     }
    113     *e = L->data[i - 1];
    114     for(i; i < L->length; i++){
    115         L->data[i - 1] = L->data[i];
    116     }
    117     L->length--;
    118     return TRUE;
    119 } 
    120 
    121 //遍历线性表
    122 Status listTraverse(SqList L){
    123     int i;
    124     for(i = 0; i < L.length; i++){
    125         printf("%d ",L.data[i]);
    126     }
    127     printf("
    ");
    128     return OK;
    129 } 
    130 
    131 //主程序
    132 int main(void){
    133     SqList L;
    134     ElemType e;
    135     initList(&L);
    136     int option = 1;
    137     int input_number;
    138     int res;
    139     ElemType input_value;
    140     printf("
    1.遍历线性表 
    2.创建线性表 
    3.清空线性表 
    4.线性表插入 
    5.查找表中元素 
    6.判断元素是否在表中 
    7.删除某个元素 
    8.线性表长度
    9.线性表是否为空
    0.退出 
    请选择你的操作:
    ");
    141     while(option){
    142         scanf("%d",&option);
    143         switch(option){
    144             case 0:
    145                 return OK;
    146                 break;
    147             case 1:
    148                 listTraverse(L);
    149                 break;
    150             case 2:
    151                 createList(&L);
    152                 listTraverse(L);
    153                 break;
    154             case 3:
    155                 clearList(&L);
    156                 listTraverse(L);
    157                 break; 
    158             case 4:
    159                 printf("请输入插入的位置:");
    160                 scanf("%d",&input_number); 
    161                 printf("
    "); 
    162                 printf("请输入插入的值:");
    163                 scanf("%d",&input_value); 
    164                 printf("
    ");
    165                 listInsert(&L, input_number, input_value);
    166                 listTraverse(L);
    167                 break;
    168             case 5:
    169                 printf("请输入要查找的位置:");
    170                 scanf("%d",&input_number);
    171                 printf("
    ");
    172                 getElem(L, input_number, &input_value);
    173                 printf("第%d个元素的值为:%d
    ",input_number,input_value);
    174                 break; 
    175             case 6:
    176                 printf("请输入要查找的元素:");
    177                 scanf("%d",&input_value);
    178                 printf("
    ");
    179                 res = locateElem(L, input_value);
    180                 if(res != ERROR){
    181                     printf("值为%d在表中的第%d个位置
    ",input_value,input_number);
    182                 }
    183                 break; 
    184             case 7:
    185                 printf("要删除第几个元素?");
    186                 scanf("%d",&input_number); 
    187                 printf("
    ");
    188                 deleteList(&L, input_number, &input_value);
    189                 listTraverse(L);
    190                 break;
    191             case 8:
    192                 res = getListLength(L);
    193                 printf("线性表的长度是:%d",res);
    194                 break;
    195             case 9:
    196                 res = listEmpty(L);
    197                 if(res){
    198                     printf("线性表的是空的");
    199                 }else{
    200                     printf("线性表的是不是空的");
    201                 } 
    202                 break;
    203         }
    204     }
    205     return OK;
    206 } 
    View Code 
  • 相关阅读:
    enmo_day_07
    enmo_day_04
    enmo_day_05
    数据仓库的模型设计
    Lucene 概念,定义应用场景
    enum 枚举的简单应用
    单例模式&synchronized
    Spark的 DAGschedule & task schedule 区别以及相互联系
    Spark的stage & job & task 到底是什么 ,以及划分原理
    Java基本数据类型&引用类型总结
  • 原文地址:https://www.cnblogs.com/xzxl/p/7545984.html
Copyright © 2011-2022 走看看