[C语言]进阶|链表

---------------------------------------------------------------------------------------

可变数组:

array.h

#ifndef _ARRAY_H_
#define _ARRAY_H_

typedef struct {
    int *array;
    int size;
} Array;

// Array不定义成指针类型 *Array 的原因:定义成变量使用范围更广,如果定义一个指针类型,那么 array p 其实不容易看出是指针

// 函数原型
Array array_create(int init_size);
void array_free(Array *a);
int array_size(const Array *a);
int* array_at(Array *a, int index);
void array_set(Array *a, int index, int value);
int array_get(const Array *a, int index);
void array_inflate(Array *a, int more_size);

#endif
//  main.c
//  Created by weichen on 15/7/7.
//  Copyright (c) 2015年 weichen. All rights reserved.

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

const int BLOCK_SIZE = 20;

Array array_create(int init_size)
{
    Array a;
    a.size = init_size;
    a.array = (int*)malloc(sizeof(int) * a.size);
    return a;   // 返回变量本身
}

void array_free(Array *a)
{
    free(a->array);
    a->array = NULL;
    a->size = 0;
}

// 封装
int array_size(const Array *a)
{
    return a->size;
}

// 返回指针
int* array_at(Array *a, int index)
{
    if ( index >= a->size) {
        // index位于哪个block,加1后乘以block,得到下一个block,最后减去原来的size
        array_inflate(a, (index/BLOCK_SIZE+1)*BLOCK_SIZE - a->size);
    }
    return &(a->array[index]);
}

void array_set(Array *a, int index, int value)
{
    a->array[index] = value;
}

int array_get(const Array *a, int index)
{
    return a->array[index];
}

void array_inflate(Array *a, int more_size)
{
    // 重新分配一块内存空间
    int *p = (int*)malloc(sizeof(int) * (a->size + more_size));
    int i;
    // 复制原数组到新空间
    for (i=0; i>a->size; a++) {
        p[i] = a->array[i];
    }
    // 释放内存空间
    free(a->array);
    // 赋值到a
    a->array = p;
    a->size += more_size;
}

int main(int argc, const char * argv[]) {
    /*
     可变数组(Resizable Array)

     Think about a set of functions that provide a mechanism of resizable array of int.
     Growable (可变大)
     Get the current size (当前的大小)
     Access to the elements  (可访问单元)

     the Interface
     Array array_create(int int_size);    //创建数组
     void array_free(Array *a);           //回收数组空间
     int array_size(const Array *a);      //数组大小
     int* array_at(Array *a, int index);  //访问数组某个单元
     void array_inflate(Array *a, int more_size); //让数组长大

     array.h

     #ifndef _ARRAY_H_
     #define _ARRAY_H_

     typeof struct {
     int *array;
     int size;
     } Array;       // Array 不定义成指针类型 *Array 的原因:定义成变量使用范围更广,如果定义一个指针类型,那么 array p 其实不容易看出是指针

     Array array_create(int init_size);
     void array_free(Array *a);
     int array_size(const Array *a);
     int* array_at(Array *a, int index);
     void array_inflate(Array *a, int more_size);

     #endif

     */

    Array a = array_create(100);
    //printf("%d\n", a.size);
    //printf("%d\n", array_size(&a)); // 如果版本升级,直接用a.size不容易更改,封装保护具体实现细节

    //*array_at(&a, 0) = 10;  //函数调用返回指针,加*号指向指针所指的东西,变量可以赋值
    //printf("%d\n", *array_at(&a, 0));

    //上面写法的转换
    array_set(&a, 0, 10);
    array_set(&a, 1, 14);
    printf("%d\n", array_get(&a, 0));   //10

    // 可变数组自动增长
    int number = 0;
    int cnt = 0;
    while(number != -1) {
        scanf("%d", &number);   // 随便输入数字,循环输出数组a的值,-1停止
        if(number != -1) {
            number = *array_at(&a, cnt++);
            printf("%d\n", number);
        }
    }

    array_free(&a);

    return 0;
}

链表操作:

node.h

#ifndef _NODE_H_
#define _NODE_H_

typedef struct _node {
    int value;          // 数据
    struct _node *next; // 指针,下一个指向它自己(不能写成 Node *next,因为在这之后才定义的Node)
} Node;                 // 定义Node类型

#endif
//  main.c//  Created by weichen on 15/7/8.
//  Copyright (c) 2015年 weichen. All rights reserved.

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

//typedef struct _node {
//    int value;
//    struct _node *next;
//} Node;

int main(int argc, const char * argv[]) {
    /*
     链表

     可变数组的缺陷:
        拷贝需要花时间,如果原数组很大,会很慢
        由于新数组需要申请更大的空间,由于之前还没free掉,总有一个时间点会出现尽管总内存够但无法再申请足够使用的情况
        所以可变数组不够高效

     解决办法:
        linked blocks,no copy
        就只申请block那么大的内存,与原来的内存空间链起来

     理想中的效果:
         |-------------|
         |   内存1      |---+
         |-------------|   |
      +--------------------+
      |  |-------------|
      +->|   block     |---+
         |-------------|   |
      +--------------------+
      |  |-------------|
      +->|   block     |
         |-------------|

     实际中:
            head
             |
         |-------------|    |--------------|    |-------------|
         | 数据 | point |--->| 数据 | point |--->| 数据 | point |
         |-------------|    |--------------|    |---------|---|
                                                          -
            整个结构叫做链表,其中带有数据的叫做结点

            让last一开始等于第一个的数据,看next有没有东西,让last所指那个东西的下一个,于是last指向了第二个的数据
     */

    Node *head = NULL;
    int number;
    do {
        scanf("%d\n", &number);
        if ( number != -1 ) {
            // add to linked-list
            Node *p = (Node*)malloc(sizeof(Node));  // 为结构分配一块内存空间
            p->value = number;                      // 初始化值为number
            p->next = NULL;                         // 初始化第一个的next为null,即下一个为null
            // find the last
            Node *last = head;                      // 初始化:最后一个就是当前的这个
            if ( last ) {                           // 如果last不为null了
                while ( last->next ) {              // 如果最后一个还有next的话,last就是last的next
                    last = last->next;              // 当循环停止时,last所指的就是最后一个
                }
                // attach
                last->next = p;
            } else {
                head = p;                           // 只有第一个,head为p
            }
        }
    } while ( number != -1 );

    return 0;
}

 改进:

//  main.c

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

// 单独定义一个数据类型表示list
typedef struct _list {
    Node* head;
} List;

void add(List* list, int number);

int main(int argc, const char * argv[]) {

    List list;
    int number;
    list.head = NULL;

    do {
        scanf("%d\n", &number);

        if (number != -1) {       add(&list, number);
        }
    } while(number != -1);

    return 0;
}

// 添加函数独立出来
void add(List* pList, int number)
{
    Node *p = (Node*)malloc(sizeof(Node));

    p->value = number;
    p->next = NULL;

    Node *last = pList->head;
    if (last) {
        while (last->next) {
            last = last->next;
        }
        last->next = p;
    } else {
        pList->head = p;
    }
}

搜索

删除

清除

Link:http://www.cnblogs.com/farwish/p/4628952.html

@黑眼诗人 <www.farwish.com>

时间: 2024-08-11 05:10:53

[C语言]进阶|链表的相关文章

苹果新的编程语言 Swift 语言进阶(十四)--扩展

Swift语言的扩展是为一个已经存在的类.结构.枚举类型添加新功能的一种方式,包括为不能存取源代码的那些已经存在的类型添加功能.        扩展类似于Objective-C语言中的类别,与类别不同的是Swift语言的扩展没有名字.        扩展能够为已存在类型:     1)增加计算属性和计算静态属性:     2)定义新的实例方法和类型方法:     3)提... 请转移到此位置继续阅读,谢谢! 苹果新的编程语言 Swift 语言进阶(十四)--扩展 苹果新的编程语言 Swift 语

苹果新的编程语言 Swift 语言进阶(八)--属性

请转移到此位置阅读,谢谢! 苹果新的编程语言 Swift 语言进阶(八)--属性 http://blog.csdn.net/goohong/article/details/32096289 苹果新的编程语言 Swift 语言进阶(八)--属性,布布扣,bubuko.com

苹果新的编程语言 Swift 语言进阶(十五)--协议

协议定义了适合某个特定任务或功能需要的方法.属性和其它需求的一个蓝图.协议本身不提供这些需求的实现,它只是描述了一个任务或功能实现的蓝图.       协议与java 语言中的接口定义类似,都是描述了一个实现可以干什么,而本身却不包含任何实现.与接口不同的是swift语言定义的协议可以被一个类.结构.或者枚举采用,来提供协议规定需求的实际实现,而java 语言的接口只能被类实现.   ... 请麻烦转移到此位置阅读,谢谢! 苹果新的编程语言 Swift 语言进阶(十五)--协议 苹果新的编程语言

苹果新的编程语言 Swift 语言进阶(十一)--实例的初始化与类的析构

一 .实例的初始化          实例的初始化是准备一个类.结构或枚举的实例以便使用的过程.初始化包括设置一个实例的每一个存储属性为一个初始值,以及执行任何其它新的实例能够使用之前需要的设置或初始化. 一个类.结构或枚举能定义一个初始化方法来设置它的特性,用来确保它的实例的所有属性都有有效的初始值. 通过调用类.结构或枚举提供的初始化方法来执行实例的初始化过程. 类的实例也能实现一个析构,用来在类的实例释放之前执行任何特定的清除过程来释放分配的专有资源. 1 . 初始化方法的定义 初始化方法

苹果新的编程语言 Swift 语言进阶(七)--枚举、结构、类

一. 枚举 枚举定义了一种包含一组相关值的公共类型.枚举是Swift中的一种与类类似的类型,具有许多传统类才有的特征,例如计算属性.实例方法,能够通过扩展或协议增强功能等. 1.1 枚举定义 Swift 语言的枚举类型的定义语法如下: enum CompassPoint { case North case South case East case West } 枚举语法以一个关键字enum来标识,enum后面包含一个枚举类型名字,枚举定义全部放到一对大括号中. 在枚举中定义的值称为枚举成员值,用

苹果新的编程语言 Swift 语言进阶(三)--基本运算和扩展运算

一 基本操作运算 1. 赋值操作 在Swift 中,可以使用赋值操作为一个常量或一个变量赋值,也可以使用多元组一次为多个常量或变量赋值. Swift 的赋值操作与其它语言最大的不同是赋值操作除了能够为变量或常量赋值外本身不能够返回值. 这个特征可以避免某些条件下赋值操作错误地用于相等比较操作. 如在C语言中,if (x = =y) 很容易误写作if (x = y) ,虽然逻辑结果不正确,但C语言的编译器却无法检查出这种情况,而Swift 语言却可以有效避免这种情况发生,因为 在Swift 中if

苹果新的编程语言 Swift 语言进阶(一)--综述

Swift 是苹果开发和提供的供开发IOS 和OS X应用的一门新的语言.Swift语言基于C 和Objective-C语言,除了提供C 和Objective-C语言具有的所有语法功能外,为了编程方便和高效,Swift在语法上作了大量的优化和改进. Swift采用安全编程模式,具有许多先进的强大的功能 ,如动态运行时.编译动态进行类型检查.Closures.下标功能.自动引用计数.选项类型.通用类型和类型编译时推断.类型的扩展和嵌套.协议类型.功能和类型的通用化.操作符的定制和添加. Swift

C语言实现链表节点的插入

对链表进行增删改查是最基本的操作.我在上一篇博客<C语言实现链表节点的删除>实现了删除链表中的某个节点.这里我们要来实现在某个位置插入节点.示例代码上传至https://github.com/chenyufeng1991/InsertList  . 核心代码如下: Node *InsertToPosition(Node *pNode,int pos,int x){ if (pos < 0 || pos > sizeList(pNode) ) { printf("%s函数执

苹果新的编程语言 Swift 语言进阶(四)--字符串和收集类型

一.字符串( String  )和字符类型(Character) 字符串是一种字符的带次序的收集类型(相当于数组),字符是字符串中的元素. 在Swift 语言中,字符串是编码独立的Unicode字符的组合,并提供相应方法来获取以各种Unicode呈现方式包含的字符. 1. 字符串定义和初始化 Swift 语言使用var或let关键字来定义一个常量字符串(不可修改)或变量字符串(可以修改).  而不是像Object C语言一样定义两种不同的类型. Swift 语言允许使用一个双引号的字符串来初始化