2020-03-30单向顺序储存&单向链表

算法与数据结构

  • 概念
    抽象数据类型是一种思考问题的方式,它隐藏繁杂的细节,只保留所需要的信息
    数据是一类相同性质元素的集合,结构就是元素之间的关系,
    按照取值不同数据类型分为原子类型,
    原子类型是不可以再分解的基本数据类型,包括,整型,浮点,字符型
    结构类型是由若干类型组合的,是可以再分解的,es结构体

  • 结构可以按逻辑结构和物理结构划分
    逻辑结构:
    线性结构:包括链表,栈(后进先出)、队列(先进先出)、字符串,可以想像成逻辑上是把一个一个数据元素串起来。
    非线性结构:树状,网状,集合,也就是图结构,树结构,集合结构
    物理结构:存储在内存中的结构,可以分为顺序存储结构、链式存储结构(内存空间不连续,但是关系是通过指针串起来的)

算法

  • 定义: 算法就是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,
    并且每个指令表示⼀个或多个操作.
    特性:a.有穷性,也就是要有出口,不能死循环 b.确定性,要有确定的输出结果 c.要有输出,输入 d可行性
    评价标准:正确性,可读性,健壮性,高效性,时间复杂度(大O表示法),空间复杂度(额外消耗的内存空间)
    大O表示法:
    常数阶 ,用1表示 O(1)
    线性阶:O(N)
    平方阶:O(N^2)
    对数阶:O(log N)
    nlogn阶:O(Nlog N)
    立方阶:O(N^3)
    指数阶:O(2^N)


    image.png
  • 数据结构的基本数据单位
    数据-> 数据对象->数据元素 -> 数据项


    数据

    image.png

非空线性列表的线性结构特点:存在唯一第一个,唯一最后一个,除第一个外都有后续,除最后一个外都有前驱

单链表特点:每个节点有数据域,指针域
image.png

通常增加头节点,这样便于首元节点的处理,非空表和空表的统一处理

传送门:https://github.com/CoderRWL/20200331-

代码演示

  • 线性顺序存储
#include <iostream>


using namespace std;
//线性数据逻辑结构 顺序存储

//自定义属于自己的宏和类型名称
#define OK 1
#define ERROR 0
#define MAXSIZE 15
typedef int ElemType;
typedef enum {faild,success}status;

//定义一个数据元素
/* 数据->数据对象->数据元素->数据项  ,其中数据元素是数据的基本单位*/
 class Person{
    ElemType *data;//使用数组来存储多个数据项
    int size;//记录当前存储数量/长度
     
   public:
     Person(){
         //申请堆空间
         data = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);//返回void *需要转换一下
         size = 0;
     }
     ~Person(){
         if (data) {
             free(data);
             size = 0;
         }
     }
     
     

     //增删改,实际中应该加锁
     
     //增
     status insertElem(ElemType e,int index){
         //保持健壮性,边界值判断,容错判断
         if (size == MAXSIZE)  return faild;//容量已达最大
         if(index > size)      return faild;//下标不对,超过最大长度
         
        //判断是否需要移动数据项
         if (index < size) {
             for (int i = size; i>index; i--) {
                 data[i] = data[i-1];
             }
         }
         
         data[index] = e;
         size++;
         
         return success;
     }
     
     //删
     status deleteElem(ElemType e){
        
         if (size == 0)  return faild;
        
         for (int i = 0; i<size; i++) {
             if (data[i] == e) {
                 //移动数据
                 for (int j = i; j<size-1; j++) {
                     data[j] = data[j+1];
                 }
                 size--;
                 break;
             }
         }
         
         return success;
     }
     
     status deleteElemAtIndex(int index){
            
         if (size == 0)  return faild;
         
         for (int j = index; j<size-1; j++) {
             data[j] = data[j+1];
         }
         size--;

         return success;
     }
     
     //改
     status modify(ElemType old_e,ElemType new_e){
         
         if (size == 0)  return faild;
         
         for (int i =0; i< size ; i++) {
             if (data[i] == old_e) {
                 data[i] = new_e;
                 //break;//只改动第一次出现的地方
             }
         }
         return success;
     }
     status modifyAtIndex(ElemType e,int index){
         
         if (size == 0)        return faild;
         if (index > size-1)   return faild;
       
         data[index] = e;
         
         return success;
     }
     
     
     //查
     status search(int index,ElemType &e){
         if (size == 0)        return faild;
         if (index > size-1)   return faild;
         
         e = data[index];
         return success;
     }
     
     //遍历打印
     status travel(){
         if (data == NULL) return faild;
             
         for (int i = 0; i<size; i++) {
             cout << data[i] << endl;
         }
         
         return success;
     }
    
};





int main(int argc, const char * argv[]) {
    // insert code here...
   cout << "Hello, World!\n";
    
    Person p;
    for (int i =0; i<10; i++) {
        p.insertElem(i, 0);
    }
    
    p.modify(5, 50);
    p.modifyAtIndex(90, 0);
    
    ElemType e ;
    p.search(4, e);//当形参是&类型时,传递时可以直接传变量名
    
    p.travel();
    
    
    return 0;
}
  • 线性链式储存
#include <stdio.h>
#include <stdlib.h>


#define MAXSIZE 15
typedef enum {faild,success}status;
typedef int ElemType;

//线性链式存储

//data存储数据,next存储与其他数据项的关系

typedef struct  Person{
    ElemType data;
    struct Person *next;
}Person;

//定义一个节点数组,注意要跟结构体指针区分开,
//typedef struct Person* personList;

//数组的地址,初始化一个数组,则把数组的地址传过来,要改变形参,需要传地址,可以这么理解
status InitPerson(Person **list){
    //创建头节点. list是数组首地址
    //先分配一个首元节点空间,后续动态添加,哨兵,一直在最第一个位置
    *list =(Person *)malloc(sizeof(Person));
    if (!*list) {
        return faild;
    }
    (*list)->data = 0;//可以赋值一些有意义的值,比如长度
    (*list)->next = NULL;
    return success;
}

//增
status Insert(Person *p,ElemType e,int index){
    
    if (!p) {
        return faild;
    }
    int k = 0;//计数
    Person *pre_p = p;
    while (pre_p && k < index) {
         //查找index-1的节点
        k++;
        pre_p = pre_p->next;
    }
    
    //如果没有哨兵,上面就要 < index-1,pre_p->next时正好来到index-1
    
    if (!pre_p) {
        return faild;//没有找到
    }
    
    /*要添加节点的关系指向下一个节点
     让前驱节点的关系指向当前节点*/
    Person *add_p = malloc(sizeof(Person));
    if (!add_p) {
        return faild;
    }
    add_p->data = e;
    add_p->next = pre_p->next;
    pre_p->next = add_p;
    return success;
}

//删
status delete(Person *p ,int index){
    //找到前后节点,删掉前后驱关系
    
    //前面判断跟增加节点是一致的
    if (!p) {
        return faild;
    }
    int k = 0;//计数
    Person *pre_p = p;
    while (pre_p && k < index) {
        //查找index-1的节点
        k++;
        pre_p = pre_p->next;
    }
    
    if (!pre_p) {
        return faild;//没有找到
    }
    
    /*让前节点的关系指向删除节点的后驱节点
     释放删除节点空间
     */
    Person *deleteP = pre_p->next;
    pre_p->next = deleteP->next;
    free(deleteP);
    
    
    return success;
    
}

//改
status modify(Person *p,ElemType e,int index){
    /*只需改动值,不需要改动关系*/
    if (!p) {
        return faild;
    }
    int k = 0;//计数
    Person *p_index = p;
    while (p_index && k <= index) {
        //查找index-1的节点
        k++;
        p_index = p_index->next;
    }
    
    if (!p_index) {
        return faild;//没有找到
    }
    
    p_index->data = e;
    
    return success;
}

//查

status search(Person *p,int index,ElemType *e){
    if (!p) {
           return faild;
       }
       int k = 0;//计数
       Person *p_index = p;
       while (p_index && k <= index) {
           //查找index-1的节点
           k++;
           p_index = p_index->next;
       }
       
       if (!p_index) {
           return faild;//没有找到
       }
    
    *e = p_index->data;
    
    return success;
    
    
}

//单链表前插和后插法

status creatHead(Person *p ,int count){
    if (!p) {
        return faild;
    }
    
    Person * p_first = p->next;
    /*
     新加入的节点指向第一个节点
     头节点指向新加入的节点
     */
    while (count-- >0) {
         Person *p_add = malloc(sizeof(Person));
        if (!p_add) {
            return faild;
        }
        
        p_add->data = count;//arc4random_uniform(100);
        p_add->next = p_first;
        p->next = p_add;
        
        p_first = p_add;
    }
    
    return success;
}

status creatAfter(Person *p ,int count){
    if (!p) {
        return faild;
    }
     Person * p_after = p;
    while (p_after->next) {
        p_after = p_after->next;
    }
    /*
     直接加到最后 ,为节点关系指向新添加节点
     */
    while (count-- >0) {
         Person *p_add = malloc(sizeof(Person));
        if (!p_add) {
            return faild;
        }
        
        p_add->data = count;//arc4random_uniform(100);
        p_after->next =p_add;
        p_after = p_add;
        if (count == 0) {
            p_after->next = NULL;
        }
    }
    
    return success;
}



void travel(Person p){
//     printf("%d\n",p.data);//哨兵可以不打印
    Person *nextp = p.next;
    while (nextp) {
        printf("%d\n",nextp->data);
        nextp = nextp->next;
    }
    
}

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!\n");
    
    
    Person *p;
    InitPerson(&p);//传地址过去,内部初始化
    for (int i = 0; i<10; i++) {
        Insert(p, i, 0);
    }
//    Insert(p, 100, 5);
//    Insert(p, 100, 11);
    
//    delete(p, 0);
//    delete(p, 8);
//
//    modify(p, 60, 2);
//
//    ElemType e;
//    search(p, 2, &e);
//
//    if (p) {
//        travel(*p);
//    }
   
 
//    creatHead(p, 10);
    creatAfter(p, 5);
    travel(*p);
    
    
    return 0;
}
  • 比较


    image.png

循环链表

  • 也就是尾节点再指向头节点


    image.png
  • 代码

//
//  main.c
//  线性循环链表
//
//  Created by  RWLi on 2020/4/1.
//  Copyright © 2020  RWLi. All rights reserved.
//

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

typedef enum{faild,success}status;
typedef int ElemType ;
typedef struct List{
    ElemType data;
    struct List* next;
}List;

status initList(List **list,ElemType e){
    *list = malloc(sizeof(List));
    if (!(*list)) {
        return faild;
    }
    (*list)->data = e;
    (*list)->next = *list;
    return success;
}
//增
status listInsert(List**L, ElemType e ,int place){//因为需要改变头节点指针,所以需要传**
    
    if (!(*L)) {
        return faild;
    }
    
    List *l_add = malloc(sizeof(List));
    l_add->data = e;
    if (!l_add) {
        return faild;
    }
    //首节点比较特殊,因为要使 L指向添加的节点
    if (place == 0) {
        
        
        /*
         查找最后的节点
         */
        List *tempL = *L;
        while (tempL->next!= (*L) ){
            tempL = tempL->next;
        }
        
        tempL->next = l_add;//为节点指向新节点
        l_add->next = *L;//新节点指向头节点
        *L =l_add;//头节点指向新节点
    }else{
        
        /*
         查找最后的节点
         */
        List *tempL = *L;
        int g= 0;
        while (tempL->next!= (*L) && g<place-1 ){
            g++;
            tempL = tempL->next;
        }
        
        
        if (tempL->next == *L) {
            //找完也没有找到,可能place 超出最大长度
            return faild;
        }
        
        
        //找到前面一个节点
        l_add->next = tempL->next;
        tempL->next = l_add;
        
    }
    
    
    return success;
}

//删
status deletList(List**L,int place){
    
    if (!(*L)) {
        return faild;
    }
    
    //处理特殊情况,删除头节点,需要改变尾节点指向
    if (place == 0) {
        
        //只有一个的时候
        if ((*L)->next == *L){
            free(*L);
            return success;
        }
        
        //找到尾节点
        List *tempL = *L;
        List *firstL = *L;
        while (tempL->next!= (*L) ){
            tempL = tempL->next;
        }
        tempL->next = (*L)->next;
        *L = (*L)->next;
        free(firstL);
        
        return success;
        
        
    }else{
        //找到删除节点前驱
        List *tempL = *L;
        int g= 0;
        while (tempL->next!= (*L) && g<place-1 ){
            g++;
            tempL = tempL->next;
        }
        if (tempL->next == *L) {
            //找完也没有找到,可能place 超出最大长度
            return faild;
        }
        
        List *deleL = tempL->next;
        tempL->next = deleL->next;
        free(deleL);
        
    }
    
    
    return success;
}

//改
status modifyList(List *L, ElemType e,int place){
    
    if (!L) {
        return faild;
    }
    
    List *modifyL = L;
    int g = 0;
    while (modifyL->next != L && g < place ) {
        modifyL = modifyL->next;
        g++;
    }
    
    if (modifyL->next == L) {
        return faild;
    }
    
    modifyL->data = e;
    
    return success;
}

//查

status searchList(List *L ,int place,ElemType  *e){
    if (!L) {
        return faild;
    }
    List *searchL = L;
      int g = 0;
      while (searchL->next != L && g < place ) {
          searchL = searchL->next;
          g++;
      }
      
      if (searchL->next == L) {
          return faild;
      }
    *e = searchL->data;
    
    
    return success;
}

void travelList(List *list){
    if (!list) {
        return;
    }
    
    List *temp = list;
    
    do {
        printf("%d\n",temp->data);
        temp = temp->next;
    } while (temp != list);
}

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!\n");
    
    List *circelList;
    
    for (int i = 0; i<10; i++) {
        if (!circelList) {
            initList(&circelList, i);
        }else{
            listInsert(&circelList, i, 0);
            
        }
    }
    
    listInsert(&circelList, 100, 5);
    listInsert(&circelList, 99, 12);
    
    deletList(&circelList, 5);
    deletList(&circelList, 9);
    deletList(&circelList, 0);
    
    modifyList(circelList, 20, 2);
    
    ElemType e;
    searchList(circelList,2,&e);
    
    travelList(circelList);
    
    return 0;
}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容