数据结构常用算法实现print

线性表的顺序表示

程序2_1.c提供了顺序存储结构下线性表的实现。第1行定义了一个常数值MAXSIZE。它是一个常数,表示线性表的最大长度。第2行把ELEMTYPE设置为int的一个别名。这样,这个例子就可以使用一组整数了。第3行到第7行包含了线性表的说明。接下来从第8行到第46行线性表运算函数的定义。

第8到第11行将线性表置成空表,只需简单地将线性表元素个数置成0即可。由于线性表的长度已经记录在结构成员length中,因此求线性表的长度(第35行到第38行)只是返回 length的值。

第20到第24行是追加函数,函数append在线性表的表尾插入一个元素。

第12行到第19行是插入函数。在表中第i位置插入一个新元素item时,需将i,i+1,…,n-1位置上的元素向后移,变成编号为i+1,i+2,…,n,然后将item插入到第i个位置,且线性表的长度加1。

第25行到第34行是删除元素。要删去表中位置i上的元素,同样需要移动表中元素,使原编号为i+1,i+2,…,n-1的元素变成编号为i,i+1,…,n-2,并将表的长度减1。

第39行到第46行的函数find在线性表中查找第一个出现的值为item的元素。如果值item找到了,函数返回元素item所在位置1,否则返回-1。

第54行到第67行是main函数的一个例子,说明了线性表的使用。57行调用clear 函数将线性表清空,第58,59,60三行调用append函数追加三个元素,第62行在位置2插入一个元素15,第65行调用delete函数删除位置3的元素。

第47行到53行的print函数是为了显示线性表中的数据而设置的。

 

 
程序2_1.c

    #define MAXSIZE 999

    typedef int ELEMTYPE;

    struct list {

        ELEMTYPE listarray[MAXSIZE];

        int length;

    };

    struct list l;

    void clear()

    {

        l.length = 0;

    }

    void insert(int pos ,ELEMTYPE item)

    {

    int i;

    for(i = l.length;i>pos;i--)

        l.listarray[i]= l.listarray[i-1];

        l.listarray[pos] = item;

        l.length++;

    }

    void append(ELEMTYPE item)

    {

        l.listarray[l.length++] = item;

    }

    ELEMTYPE delete(int pos)

    {

        int i;

        ELEMTYPE temp;

        temp = l.listarray[pos];

        for(i = pos;i<l.length-1;i++)

 

 

            l.listarray[i] = l.listarray[i+1];

        l.length--;

        return temp;}

    int length()

    return l.length;    }

    int find(ELEMTYPE item)

    {int i;

        for (i=0;i<l.length;i++)

            if (l.listarray[i] == item)

                return i;

        return -1; }

    void print()

    {int i;

     for(i=0;i<l.length;i++)

        printf("%d ",l.listarray[i]);

    printf("\n");}

    void main()

    {clrscr();

        clear();

        append(10); /* L is 10 */

        append(20); /* L is (10,20) */

        append(30); /* L is (10,20,30) */

        print();

        insert(2,15);   /* L is (10,20,15,30) */

        print();

        printf("\n%d",find(100));

        printf("\n%d\n",delete(3)); /*L is (10,20,15) */

        print();}

 

 

 

线性表的链式表示

程序2_2.c提供了链式存储结构下线性表的实现。第3行到第8行包含了线性表中结点的说明,其中element表示数据域,存放该结点的数据信息,next为指针域,指明该结点的唯一后继结点在内存中的存放地址,或是在该结点序列中所在的物理位置。线性链表由head和tail表示。接下来从第9行到第76行线性表运算函数的定义。第9行到第14行初始化单链表。head指针与tail指针指向表头结点。

在单链表的最后一个结点后插入一个结点只要将单链表尾指针tail指向新插入结点,新插入结点成为最后一个结点即可。第15行到第20行函数append实现追加一个新结点到单链表的最后,新结点的元素值为item。malloc是C语言提供的标准函数,其功能是申请存储空间。

设p是指向单链表中一个结点的指针,在p指向的结点后面插入一个结点包括三个步骤。首先,要创建一个新的结点,并且赋给它一个新的值。其次,新结点的next指向指针p指向结点的后继结点。第三,指针p指向的结点的next要指向新插入的结点。

    第21行到第38行函数insert实现在单链表的第i个结点前面插入一个新结点。新结点的元素值为item,s为指向新结点的指针。算法在实现时,首先查找新结点插入位置,然后根据上面所述修改相应指针。

从单链表删去一个结点只需将被删结点的前趋结点的next域指向被删结点的后继结点即可。但必须注意,被删结点占据的内存空间应该返回给存储器。因此可设一个临时指针指向要删去的结点,而后调用C语言提供的标准过程free将被删去的结点占据的内存空间返回给存储器。第39行到第57行的函数delete实现删除结点运算。

第58行到第65求单链表中所含结点的个数。为求单链表的结点个数,我们必须从单链表表头开始,沿着每个结点的链指针,依次向后访问并计数,直到最后一个结点位置。

 

程序2_2.c

    #include <alloc.h>

#include<stdio.h>

    typedef int ELEMTYPE;

    struct list {

        ELEMTYPE element;

        struct list *next;

    };

    struct list *head;

    struct list *tail;

    void init()

    {

        head = malloc(sizeof(struct list));

        head->next = NULL;

    tail = head;

    }

    void append(ELEMTYPE item)

    {

        tail=tail->next=(structlist*)malloc(sizeof(struct list));

        tail->element = item;

        tail->next = NULL;

    }

    int insert(int pos,ELEMTYPE item)

    {

        struct list *p,*s;

        int j;

        s = (struct list *)malloc(sizeof(structlist));

        s->element = item;

        p = head;

        j = 1;

        while ((p!=NULL) && (j<pos)){

            p = p->next;

            j++;

        }

        if((!p)||(j>pos)) return 0;

        s->next = p->next;

        p->next = s;

        if (tail == p) tail = s;

        return 1;

    }

    ELEMTYPE delete(int pos)

    {

        struct list *p,*q;

        ELEMTYPE temp;

        int j;

        q = p;  p= head->next;

        j = 1;

        while ((p!=NULL) && (j<pos)){

            q = p; p = p->next;

            j++;

        }

        if((!p)||(j>pos))

            return 0;

        q->next = p->next;

        temp = p->element;

        if (tail == p) tail = q;

        free(p);

        return temp;

    }

    int length()

    {

        struct list *p;

        int cnt = 0;

        for (p = head->next;p != NULL;p =p->next)

            cnt++;

        return cnt;

    }

    int find(ELEMTYPE item)

{

        struct list *p = head->next;

        while (p!=NULL) {

            if (p->element == item)

                return 1;

            else

                p = p->next;

        }

        return 0;

    }

    void print()

    {

        struct list *p;

        printf("\n");

        for (p =head->next;p!=NULL;p=p->next)

            printf("%d",p->element);

    }

    void main()

    {

        clrscr();

        init();

        append(10); /* list is (10) */

        append(20); /* list is (10,20) */

        append(30); /* list is (10,20,30) */

        append(40); /* list is (10,20,30,40) */

        insert(3,35);   /* list is (10,20,30,35,40) */

        print();

        printf("\n%d\n",delete(4)); /* list is (10,20,30,35) */

        print();

    }

程序2_3.c是栈数据结构的实现,第3行到第6行包含栈类型的说明, top被定义为表示栈中最上面那个元素的位置。

push(第13行到第17行)和pop(第18行到第22行)只是从top指示的数组中的位置插入和删去一个元素,因为top表示栈顶元素的位置,所以push首先把一个值插入到栈顶位置,然后把top加1。同样,pop首先把top减1,然后删去栈顶元素。

       函数topValue(第23行到27行)只是将栈顶元素返回。如果栈中没有元素,函数isEmpty(第28行到第31行)返回1,否则返回0。

程序2_3.c

    #include <assert.h>

    #define MAXSIZE 100

    typedef int ELEMTYPE;

    struct stack {

        ELEMTYPE listarray[MAXSIZE];

        int top;

    };

    struct stack s;

    void init()

    {

        s.top = 0;

    }

    void push(ELEMTYPE item)

    {

        assert(s.top<MAXSIZE);

        s.listarray[s.top++] = item;

    }

    ELEMTYPE pop()

    {

        assert(!isEmpty());

        return s.listarray[--s.top];

    }

    ELEMTYPE topValue()

    {

        assert(!isEmpty());

        return s.listarray[s.top-1];

    }

    int isEmpty()

    {

        return s.top == 0;

    }

    void main()

    {

        init();

        push(10);   /* s is (10) */

        push(20);   /* s is (20,10) */

        printf("%d",topValue());    /*return top element 20*/

        printf("%d",pop()); /* s is (10) */

    }

 

程序2_4.c给出了链式栈表示和各种运算的算法。其中top是指向链式栈第一个结点(栈顶)的指针。

进栈操作(第13行到第21行)首先申请一个新结点,并初始化该结点,然后修改新产生的结点的next域指向栈顶,并设置top指向新的链表结点。

第22行到第32行是出栈操作。变量temp用来存储栈顶结点的值,ltemp用于在删去栈顶结点时保持与栈的链接,它指向当前栈顶链接到的结点。此时把原来的栈顶结点释放回内存,恢复top等于ltemp。也就是指向原来栈顶链接的结点,原来栈顶的值temp作为pop函数的返回值。

程序2_4.c

    #include <alloc.h>

    #include <assert.h>

    typedef int ELEMTYPE;

    struct node {

        ELEMTYPE elem;

        struct node *next;

    };

    struct node *top;

    void init()

    {

        top = NULL;

    }

    void push(ELEMTYPE item)

    {

        struct node *p;

        if ((p=(struct node *)malloc(sizeof(structnode)))!=NULL){

            p->elem = item;

            p->next = top;

            top = p;

        }

    }

    ELEMTYPE pop()

    {

        ELEMTYPE temp;

        struct node *ltemp;

        assert(!isEmpty());

        temp = top->elem;

        ltemp = top->next;

        free(top);

        top = ltemp;

        return temp;

    }

    ELEMTYPE topValue()

    {

        assert(!isEmpty());

        return top->elem;

    }

    isEmpty()

    {

        return top == NULL;

    }

    void main()

    {

        init();

        push(10);   /* s is (10) */

        push(20);   /* s is (20,10) */

        push(30);   /* s is (30,20,10) */

        printf("%d",topValue());

        printf("%d",pop()); /* s is (20,10)*/

    }

 

队列

在程序2_5.c中,q表示循环队列(第3行到第9行),其队头与队尾指示变量分别为front和rear。队列中的元素类型为int(第3行)。函数enqueue(第14行到第19行)执行队列的插入操作,参数item是插入队列的元素。当队列不满时,enqueue首先移动队尾指针,然后将item置入rear所指位置。函数dequeue(第20行到25行)执行队列的删除操作,返回从队列中取出的元素。函数firstValue(第26行到第30行)返回队列头元素。

 

程序2_5.c

    #include <assert.h>

    #define MAXSIZE 100

    typedef int ELEMTYPE;

    struct queue {

        intfront;

        intrear;

        ELEMTYPEelem[MAXSIZE];

    };

    struct queue q;

    void init()

    {

    q.front = q.rear = 0;

    }

    void enqueue(ELEMTYPE item)

    {

        assert(((q.rear+1)% MAXSIZE) != q.front);

        q.rear= (q.rear + 1) % MAXSIZE; /* increment rear */

        q.elem[q.rear]= item;

    }

    ELEMTYPE dequeue()  /* dequeue element fro front of queue */

    {

        assert(!isEmpty()); /* there must be somethingtodequeue */

        q.front= (q.front + 1) % MAXSIZE;  /* incrementfront */

        returnq.elem[q.front]; /* return value */

    }

    ELEMTYPE firstValue() /* get value of frontelement */

    {

    assert(!isEmpty());

        returnq.elem[(q.front+1) % MAXSIZE];

    }

    int isEmpty()   /* TRUE is queue is empty */

{

        returnq.front == q.rear;

    }

    void main()

    {

        init();

        enqueue(10);   /* q is (10)

        enqueue(20);   /* q is (10,20)

        enqueue(30);    /* q is (10,20,30)

        printf("%d",firstValue());  /* will display 10 */

        printf("%d",dequeue());     /* will displa 10 */

    }

程序2_6.c给出了链式队列的说明和函数的实现。front和rear分别是指向队首和队尾元素的指针。链式队列的实现不需要表头结点,当队列为空时,指针front和rear的值均为空(NULL)。

当在队列中插入一个结点时(第14行到27行),新结点链入rear所指结点的next域,并使rear指向新的结点。如果在插入之前队列为空,则指针front指向新插入的结点。当从队列中删除一个结点时(第28行到37行),要把front所指结点的next域的值赋给front,并且释放这个结点。如果删除之后队列为空,则置指针rear为空(NULL)。

程序2_6.c

    #include <alloc.h>

    #include <assert.h>

    typedef int ELEMTYPE;

    struct node {

        ELEMTYPEelem;

        structnode *next;

    };

    struct node *front;

    struct node *rear;

    void init()

    {

        rear= front = NULL;

    }

    void enqueue(ELEMTYPE item)

    {

        if(rear != NULL) {

            rear->next=(structnode *)malloc(sizeof(struct node));

            rear->next->elem= item;

            rear->next->next= NULL;

            rear= rear->next;

        }

        else{

            front=rear=(structnode *)malloc(sizeof(struct node));

            front->elem= item;

            front->next = NULL;

        }

    }

    ELEMTYPE dequeue()

    {

        ELEMTYPEtemp = front->elem;

        structnode *ltemp = front;

        assert(!isEmpty());

        front= front->next;

        free(ltemp);

        if(front==NULL) rear = NULL;

        returntemp;

    }

    ELEMTYPE firstValue()

    {

        assert(!isEmpty());

        returnfront->elem;

    }

    int isEmpty()

    {

        returnfront == NULL;

    }

    void main()

    {

        init();

        enqueue(10);

        enqueue(20);

        enqueue(30);

        printf("%d",firstValue());

        printf("%d",dequeue());

    }

 


稀疏矩阵

程序3_1.c是按照快速转置算法求矩阵的转置。程序第2行给出稀疏矩阵a的三元组表表示。函数FastTranspose按照快速转置算法思想将稀疏矩阵a转置为稀疏矩阵b,b也表示为三元组表形式。第11行到第13行计算矩阵a的每一列的非零元素个数。第15行计算a中每一列第一个非零元素在b中的起始位置。第16行第22行对a中的元素依此进行转置。

 

程序3_1.c

       #define MAXCOL 100

    int a[][3] ={{7,6,8},{0,0,5},{0,3,2},{0,5,8},{1,1,6},

              {1,2,9},{2,3,3},{4,0,9},{5,2,2}};

    int b[9][3];

    FastTranspose(inta[][3],int b[][3])

    {

        intm,n,tn,i,j;

        int s[MAXCOL],t[MAXCOL];

        m = a[0][0];    n= a[0][1];    tn = a[0][2];

        b[0][0] = n;    b[0][1]= m;    b[0][2] = tn;

        if (tn<=0) return;

        for (i = 0;i < n;i++) s[i] = 0;

        for (i = 1;i <= tn;i++)

            s[a[i][1]] = s[a[i][1]] + 1;

        t[0] = 1;

        for (i = 1;i < n;i++)   t[i]=t[i-1]+s[i-1];

        for (i = 1;i <= tn;i++) {

            j = a[i][1];

            b[t[j]][0] = a[i][1];

            b[t[j]][1] = a[i][0];

            b[t[j]][2] = a[i][2];

            t[j] = t[j] + 1;

        }

    }

    main()

    {

        int i;

        clrscr();

        for (i=0;i<=8;i++)

            printf("%d %d%d\n",a[i][0],a[i][1],a[i][2]);

        FastTranspose(a,b);

        printf("\n");

        for (i=0;i<=8;i++)

            printf("%d %d%d\n",b[i][0],b[i][1],b[i][2]);

    }

程序3_2.c是求矩阵的乘积。程序第1行给出稀疏矩阵a的行数,程序第2行给出稀疏矩阵a的列数(b的行数),程序第3行给出稀疏矩阵的列数。第4行和第5行给出矩阵a与b的三元组表。第6行定义存放a与b相乘的结果c(二维数组)。

第7行到第27行的MatrixMultiply函数实现稀疏矩阵相乘。此算法中数组S和T的意义与矩阵转置中相同,分别表示矩阵B中各行非零元素个数和各行第一个非零元素在数组b中的位置。在找B中某行的所有非零元素时,只要知道此行第一个非零元素在b中的位置和下一行第一个非零元素在b中的位置即可。例如,在B中行号为i所有非零元素,就是在b中从T[i]到T[i+1]-1的这些元素。对于在B中最后一行n,实际上它没有“下一行”了,只是为了求T[n+1],又虚设了第n+1行,且T[n+1]的值为 t2+1。

程序3_2.c

    #define M 3

    #define P 4

    #define N 2

    int a[][3]={{3,4,4},{0,0,3},{0,3,2},{1,1,1},{2,0,2}};

    int b[][3]={{4,2,3},{0,1,2},{2,0,2},{3,1,1}};

    int c[M][N];

    MatrixMultiply()

    {

        intm,n,t1,t2,i,j,p,k;

        ints[P],t[P];

        m =a[0][0];    n = a[0][1];    t1 = a[0][2];

        if (n ==b[0][0]) {

            p =b[0][1];

            t2 =b[0][2];

        }

        if(t1*t2 == 0) return;

        for (i =0;i < n;i++) s[i] = 0;

        for (i =1;i <= t2;i++)

            s[b[i][0]]= s[b[i][0]] + 1;

        t[0] = 1;

        for (i =1;i < n+1;i++) t[i]=t[i-1]+s[i-1];

        for (i =1;i <= t1;i++) {

            k =a[i][1];

            for(j= t[k];j <= t[k+1]-1;j++)

                c[a[i][0]][b[j][1]]+= a[i][2]*b[j][2];

        }

    }

    main()

    {

        int i,j;

        clrscr();

        MatrixMultiply();

    }

周游二叉树

在程序4_1.c中,函数inorder实现中序周游二叉树的递归算法,周游时输出所访问结点的值。程序中第2行定义二叉树结点元素类型为字符型,第3行到第7行定义二叉树结点类型,第8行定义root为二叉树的根结点指针。

第24行到第31行的inorder函数首先检查树是否为空(如果为空,则周游完成;并且函数直接返回),否则对左子树递归调用本函数,当左子树周游完成后,对根结点调用printf函数打印结点的值(或者按照需要完成某些运算)。最后,对右子树进行同样的操作。

setup函数利用前序结果序列建立二叉树。Setup扫描一个字符串,若当前字符不为‘.’,则申请一个结点,存入当前字符,并置该结点的左、右指针为空。然后用该结点的左链和右链存放子树根结点的指针,递归调用函数setup,建立当前结点的左子树和右子树。当到达字符串的末尾时,建立二叉树的过程结束。

第32行到第37行是main函数的一个例子,首先调用函数setup建立一棵二叉树。然后调用inorder函数对二叉树进行中序周游。

 

程序4_1.c

    #include <alloc.h>

    typedef char ELEMTYPE;

    struct BinNode {

        ELEMTYPE element;

        struct BinNode *left;

        struct BinNode *right;

    };

    struct BinNode *root;

    void setup(struct BinNode **t)

    {

        ELEMTYPE ch;

        struct BinNode *p;

        scanf("%c",&ch);

        if (ch == '.')

            *t = NULL;

        else {

            p = (struct BinNode*)malloc(sizeof(struct BinNode));

            p->element = ch;

            *t = p;

            setup(&(p->left));

            setup(&(p->right));

        }

    }

    void inorder(struct BinNode *t)

    {

        if (t != NULL) {

            inorder(t->left);

            printf("%c",t->element);

            inorder(t->right);

        }

    }

    void main()

    {

         clrscr();

         setup(&root);

        inorder(root);

    }

 

程序4_2.c实现二叉树周游的非递归算法。为了实现非递归算法,要在程序中设置一个栈结构,用以保存指向结点的指针,以便能够继续周游。

第16行到第33是第3章中顺序栈的实现。第34行到第48行的函数setup与程序4_1.c功能相同。

第49行到第63的inorder函数实现二叉树中序周游。对于inorder函数来说,首先从二叉树的根结点开始周游,令指针变量p指向当前访问结点,只是在访问结点之前,若p所指结点的左链不空,则沿着其左链前进,在前进过程中,把经过的结点指针值逐一压栈。这个过程一直重复到p为空,从而实现周游左子树。然后,如果栈不空,则从栈中弹出一个结点的指针值,访问这个结点。接下来,p取其右链的值,实现周游右子树。整个周游过程是在一个do-while循环中进行。只有当p为空,而且栈也为空时,do-while循环结束,周游结束。

 

程序4_2.c

    #include <alloc.h>

    #include <assert.h>

    #define MAXSIZE 100

    typedef char ELEMTYPE;

    struct BinNode {

        ELEMTYPE element;

        struct BinNode *left;

        struct BinNode *right;

    };

    struct stack {

        struct BinNode *listarray[MAXSIZE];

        int top;

    };

    struct BinNode *root;

    struct stack s;

    void init()

    {

        s.top = 0;

    }

    void push(struct BinNode *item)

    {

        assert(s.top<MAXSIZE);

        s.listarray[s.top++] = item;

    }

    struct BinNode *pop()

    {

        assert(!isEmpty());

        return s.listarray[--s.top];

    }

    int isEmpty()

    {

        return s.top == 0;

    }

    void setup(struct BinNode **t)

    {

        ELEMTYPEch;

        struct BinNode *p;

        scanf("%c",&ch);

        if (ch == '.')

            *t = NULL;

        else {

            p = (struct BinNode*)malloc(sizeof(struct BinNode));

            p->element = ch;

            *t = p;

            setup(&(p->left));

            setup(&(p->right));

        }

    }

    void inorder(struct BinNode *t)

    {

        struct BinNode *p = t;

        do {

            while (p != NULL) {

                push(p);

                p = p->left;

            }

            if (!isEmpty()) {

                p = pop();

                printf("%c",p->element);

                p = p->right;

            }

        }while (!(p == NULL &&isEmpty()));

    }

    void main()

    {

         clrscr();

         init();

         setup(&root);

         inorder(root);

    }

Huffman树

程序4_3.c按照Huffman算法由已知的权集构造Huffman树并求Huffman编码。第2行定义权集元素个数。第3行定义Huffamn树结点个数。第4行到第9行定义Huffamn树结点类型,结点类型由权值、双亲、左子树和右子树组成。第10行到第13行定义Huffamn编码结构,由存放编码的数组和编码的开始位置组成。第14行的数组weight存放权值,第15   行数组  HT用来存放Huffman树,第16行数组HC用于存放Huffman编码。

       第17行到26行的init函数用于初始化Huffman树。将由n个权值作为叶结点存放到数组HT的前n个分量中。

       第27行到38行函数minimum从数组weight中求出当前最小的元素,并用一个大数HUGE把weight中的最小元素冲掉,返回最小元素所在位置。函数huffmantree按照huffman算法的基本思想,不断将两个子树合并为一个较大的子树,每次构成的新子树的根结点顺序存放到数组HT中的前n个分量的后面。

       函数huffmancode求每个叶结点的huffman编码。从该叶结点开始,沿结点的双亲域回退到根结点,每回退一步,就走过了huffman树中的一个分支,从而得到一位huffman编码值。对于第i个叶结点,其huffman编码存放在HC[i].bit中从HT[i].start到n的分量上。

程序4_3.c

    #define HUGE 999

    #define N 8

    #define M 2*N-1

    struct HuffmanNode {

        int weight;

        int parent;

        int left;

        int right;

    };

    struct HuffmanCode {

        int bit[10];

        int start;

    };

    int weight[] ={5,29,7,8,14,23,3,11,0,0,0,0,0,0,0};

    struct HuffmanNode HT[M];

    struct HuffmanCode HC[N];

    void init()

    {

        int i;

        for (i=0;i<M;i++) {

            HT[i].parent = 0;

            HT[i].weight = weight[i];

            HT[i].left = 0;

            HT[i].right = 0;

        }

    }

    int minimum()

    {

        int i,k;

        int min = HUGE;

        for (i=0;i<M;i++)

            if (min>weight[i] &&weight[i] != 0) {

                min = weight[i];

                k = i;

            }

        weight[k] = HUGE;

        return k;

    }

    void huffmantree()

    {

        int i,l,r;

        for (i=N;i<M;i++) {

            l = minimum();

            r = minimum();

            HT[l].parent = i;

            HT[r].parent = i;

            HT[i].left = l;

            HT[i].right = r;

            HT[i].weight = HT[l].weight +HT[r].weight;

            weight[i] = HT[i].weight;

        }

    }

    void huffmancode()

    {

        int i,p,j,c;

        struct HuffmanCode cd;

        for(i=0;i<N;i++) {

            cd.start = N-1;

            c = i;

            p = HT[c].parent;

            while (p != 0) {

                if (HT[p].left == c)

                    cd.bit[cd.start] = 0;

                else cd.bit[cd.start] = 1;

                cd.start--;

                c = p;

                p = HT[c].parent;

            }

            for(j=cd.start+1;j<N;j++)HC[i].bit[j] = cd.bit[j];

            HC[i].start = cd.start;

        }

    }

    void main()

    {

        int i,j;

        clrscr();

        init();

        huffmantree();

        for (i=0;i<M;i++)

        printf("%d%d%d%d\n",HT[i].weight,HT[i].parent,HT[i].left,HT[i].right);

        printf("\n");

        huffmancode();

        for (i=0;i<N;i++) {

            printf("%5d:",HT[i].weight);

            for (j=HC[i].start+1;j<N;j++)

                printf("%d",HC[i].bit[j]);

            printf("\n");

        }

    }

深度优先遍历

在程序5_1.c,我们用邻接表表示图。用一维数组visited[w]标记顶点w是否被访问过。程序第3行到第7行定义图的邻接表存储结构。

函数setup建立n个顶点的邻接表,该函数首先将邻接表的头结点初始化为空(第14行),然后依次输入相邻顶点(vi  vj),并将vj链入vi的链表中。输入过程直到出现(vi=0  vj=0)结束。

第24行到第37行的函数print用于打印邻接表的全部内容。在打印的结果中,第一列整数为图中各顶点的序号,同一行的是该顶点的相邻顶点。

第38行到第52行的dfs函数实现以参数v为起点的深度优先搜索。指针p指向顶点v的第一个相邻顶点,在执行函数dfs时沿着v的邻接表前进。

 

程序5_1.c

    #include <alloc.h>

    #define MAXVERTEX 100

    struct EdgeNode {

        int vertex;

        struct EdgeNode *next;

    };

    struct EdgeNode *a[MAXVERTEX];

    int visited[MAXVERTEX];

    void setup(int n)

    {

        int vi,vj;

        int i;

        struct EdgeNode *p;

        for (i=0;i<n;i++)   a[i] = NULL;

        scanf("%d%d",&vi,&vj);

        while (vi>=0) {

            p = (struct EdgeNode*)malloc(sizeof(struct EdgeNode));

            p->vertex = vj;

            p->next = a[vi];

            a[vi] = p;

        scanf("%d%d",&vi,&vj);

        }

    }

voidprint(int n)

    {

        struct EdgeNode *p;

        int i;

        for (i=0;i<n;i++) {

        printf("%d ",i);

            p = a[i];

            while (p != NULL) {

                printf("%d",p->vertex);

                p = p->next;

            }

        printf("\n");

        }

    }

    void DFS(int v)

    {

        struct EdgeNode *p;

        int i;

        visited[v] = 1;

        p = a[v];

    while (p != NULL) {

            i = p->vertex;

            if (!visited[i]) {

                printf(" (%d,%d)",v,i);

                DFS(i);

            }

            p = p->next;

    }

    }

    void main()

    {

        int n,i;

        clrscr();

        printf("Please input vertex numberof graph: ");

    scanf("%d",&n);

        for (i=0;i<n;i++) visited[i] = 0;

        setup(n);

        print(n);

        printf("Order in travers bydfs...");

        DFS(0);

    }

最小生成树

       在程序5_2.c中,第1行定义常量HUGE为大于图中边的权最大值,第3行到第8行给出了加权图的邻接矩阵,其中N为图的顶点个数。

第9行到第36行的函数prim实现Prim算法,在这个函数里,matrix表示带权图的邻接矩阵。为了便于选出权最小的边,我们引入两个数组CloseVertex和LowCost,CloseVertex[i]表示最小代价生成树中的一个顶点,该顶点和不是最小代价生成树中的一个顶点i构成的边(CloseVertex[i],i)具有最小的权。LowCost[i]表示边(CloseVertex[i],i)的权。起初(第14行到第17行)我们将顶点0作为生成树的顶点,所以,CloseVertex[i]的值为0,i=1,2,…,n-1。而LowCost[i]为边(0,i)的权,i=1,2,…,n-1。由于n个顶点的连通图共有n-1条边,所以,选择边的过程共需要重复n-1次。每次扫描数组LowCost,找出当前与生成树中顶点最近的顶点,令其为w,得到生成树的一条边(w,CloseVertex[w])(第23行到第27行)。然后,令LowCost[w]=0(表示顶点w已在最小生成树中),由于顶点w加入最小生成树中后,可能引起其它顶点的LowCost发生变化,因此第30行到第34行修改数组LowCost和CloseVertex。

第37到第45行的PrintMatrix函数输出加权图的邻接矩阵。

 

程序5_2.c

    #define HUGE 999

    #define N 6

    int matrix[N][N] = {{0,60,10,50,HUGE,HUGE},

                        {60,0,50,HUGE,30,HUGE},

                        {10,50,0,50,60,40},

                        {50,HUGE,50,0,HUGE,20},

                        {HUGE,30,60,HUGE,0,60},

                        {HUGE,HUGE,40,20,60,0}};

    int Prim(int matrix[N][N],int n)

    {

        inti,j,k,MinCost;

        intLowCost[N];

    int CloseVertex[N];

        for(i=1;i<n;i++) {

            LowCost[i]= matrix[0][i];

        CloseVertex[i] = 0;

        }

        LowCost[0]= 0;

        CloseVertex[0]= 0;

        for(i=1;i<n;i++) {

            MinCost= HUGE;

            k= i;

        for (j=1;j<n;j++)

                if (LowCost[j] < MinCost &&LowCost[j]!=0) {

                    MinCost= LowCost[j];

                k = j;

                }

            printf("(%d,%d)",k,CloseVertex[k]);

            LowCost[k]= 0;

            for(j=1;j<n;j++)

            if (matrix[k][j]<LowCost[j]) {

                    LowCost[j]= matrix[k][j];

                    CloseVertex[j]= k;

                }

        }

    }

    void PrintMatrix(int matrix[N][N],int n)

    {

        inti,j;

        for(i=0;i<n;i++) {

        for(j=0;j<n;j++)

                printf("%5d",matrix[i][j]);

            printf("\n");

        }

    }

    void main()

    {

        clrscr();

        PrintMatrix(matrix,N);

        Prim(matrix,N);

    }

拓扑排序

程序5_3.c中,第4行到第7行定义邻接表头结点类型,头结点中有两个字段count和link。Count字段存放该顶点的入度,link是一个指向该结点邻接表的第一个表结点的指针。第8行到第11行定义表结点类型。每个表结点有两个字段:vertex和next。

第13行到30行函数AdjList生成图邻接表。在该函数中利用头结点的count记录顶点的直接前驱数。

第45行到第71行函数TopOrder实现拓扑排序。首先将前驱为0的顶点入栈,栈通过count字段连接起来。第55行到第70行从栈中取出一个顶点并输出,然后将该顶点的邻接表上所有顶点的前驱计数递减,如果前驱计数为0则入栈,这个过程重复n次。

 

程序5_3.c

    #include <alloc.h>

    #define MAXVERTEX 100

    #define N 7

    struct EdgeNode {

        int vertex;

        struct EdgeNode *next;

    };

structVertexNode {

        int count;

        struct EdgeNode *link;

    };

    struct VertexNode AdjList[N];

    void AdjList(struct VertexNode a[],int n)

    {

        int vi,vj,i;

        struct EdgeNode *p;

    for (i=0;i<n;i++) {

            a[i].count = 0;

            a[i].link = NULL;

        }

        scanf("%d%d",&vi,&vj);

        while (vi>=0) {

        p = (struct EdgeNode*)malloc(sizeof(struct EdgeNode));

            p->vertex = vj;

        p->next = a[vi].link;

            a[vi].link = p;

            a[vj].count = a[vj].count + 1;

            scanf("%d%d",&vi,&vj);

    }

 

    void PrintAdjList(struct VertexNode a[],intn)

    {

        int i;

        struct EdgeNode *p;

    for (i=0;i<n;i++) {

            printf("%d %d ",i,a[i].count);

            p = a[i].link;

            while (p != NULL) {

                printf("%d",p->vertex);

            p = p->next;

            }

            printf("\n");

        }

}

voidTopOrder(struct VertexNode a[],int n)

{

        int i,j,k,top;

        struct EdgeNode *ptr;

        top = -1;

    for (i=0;i<n;i++)

            if (a[i].count == 0) {

                a[i].count = top;

            top = i;

            }

        for (i = 0;i < n;i++) {

            if (top == -1) return;

            j = top;

        top = a[top].count;

            printf("%d",j);

            ptr = a[j].link;

            while (ptr != NULL) {

                k = ptr->vertex;

                a[k].count = a[k].count - 1;

            if (a[k].count == 0) {

                a[k].count = top;

                    top = k;

                }

                ptr = ptr->next;

            }

        }

    }

voidmain()

    {

        AdjList(AdjList,N);

        PrintAdjList(AdjList,N);

        TopOrder(AdjList,N);

    }

 

单元最短路径

Dijkstra算法的执行过程是:首先从S之外的顶点集合V-S中选出一个顶点u,使distance[u]值最小,我们把u加入到集合S中(S[u]=1),顶点u也成为S中的一员。这时v0出发,中间只经过S中的顶点并以不在S中的一个顶点w为终点的最短路径长度可能会减小。就是说,distance[w]的值可能发生变化。如果distance[w]的值真的发生了变化(减小),是因为有一条从v0到u,再到w的路径,而且v0到u的路径为最短的这种路径,自u到w的路径是边<u,w>的缘故。这条路径长度是distance[u]+matrix[u][w]。因此接下来要调整distance中记录的从源点到V-S中每个顶点v的最短路径长度:从原来的distance[v]和distance[u]+matrix[u][v]中选择较小值作为新的distance[v],使distance[v]始终保持到目前为止最短的路径长度。重复上述过程,直到S中包含V中的全部顶点。结果数组distance记录了从源点到图中其余各顶点的最短路径长度。

    在程序5_4.c中,为了实现从“S之外的顶点集合V-S中选出一个顶点u,使distance[u]值最小”的目的,我们建立函数MinCost,选择当s[u]为0时,使distance[u]最小的w,并返回w的值。函数ShortPath按上述说明实现Dijkstra算法。函数PrintMatrix输出图邻接矩阵的值。

 

程序5_4.c

    #define HUGE 999

    #define N 5

    int matrix[N][N] = {{0,10,2,30,HUGE},

                        {HUGE,0,HUGE,15,HUGE},

                        {HUGE,3,0,HUGE,10},

                        {HUGE,HUGE,HUGE,0,6},

                        {HUGE,HUGE,HUGE,HUGE,0}};

intdistance[N];

voidShortPath(int matrix[N][N],int v0,int n)

    {

        int i,u,dist,number;

        int s[N];

        for (i=0;i<n;i++) {

            s[i] = 0;

        distance[i] = matrix[v0][i];

        }

        s[v0] = 1; number = 1;

    while (number<n) {

            u = MinCost(distance,s,n);

            s[u] = 1;

            number++;

        for (i=0;i<n;i++) {

                if (s[i] == 0) {

                    dist = distance[u] +matrix[u][i];

                distance[i]=(distance[i]<dist)?distance[i]:dist;

                }

        }

        }

    }

    int MinCost(int distance[],int s[],int n)

    {

        int i,k;

        int MinDistance = HUGE;

        for (i=0;i<n;i++)

            if (s[i] == 0 && distance[i]< MinDistance) {

                MinDistance = distance[i];

            k = i;

            }

        return k;

    }

    void PrintMatrix(int matrix[N][N],int n)

{

        int i,j;

        for (i=0;i<n;i++) {

            for(j=0;j<n;j++)

                printf("%5d",matrix[i][j]);

            printf("\n");

        }

    }

    void main()

    {

        int i;

        clrscr();

        PrintMatrix(matrix,N);

        ShortPath(matrix,0,N);

        for (i=1;i<N;i++) printf("(0 -%d) : %d\n",i,distance[i]);

    }

 

 

 


顺序查找

程序6_1.c实现顺序查找。第2行定义了一个常整数N表明查找表的大小。函数init随机产生N个数并将其置入查找表a中。

程序6_1.c

    #include <stdlib.h>

    #define N 8

    int a[N];

    void init(int a[],int n)

    {

        int i;

    for (i = 0;i < n;i++)

            a[i] = random(100);

    }

    void print(int a[],int n)

    {

        int i;

        for (i = 0;i < n;i++)

            printf("%d ",a[i]);

        printf("\n");

    }

intsearch(int a[],int k,int n)

    {

    int i = 0;

        for (i = 0;i < n && a[i] !=k;i++);

        if (i<n)

            return i;

        else

            return -1;

}

    void main()

    {

        int k;

        clrscr();

        init(a,N);

        print(a,N);

        printf("Please input KEY :");scanf("%d",&k);

        printf("\n%d ",search(a,k,N));

        printf("\nPress any key toRETURN...");

        getche();

    }


折半查找

程序6_2.c实现折半查找。第3行对查找表中元素赋值,且值有序。在函数search中,如果查找下限小于上限,则计算中间位置。并根据中间位置的元素值与k进行比较,根据比较结果决定下次查找的范围。

 

程序6_2.c

    #include <stdlib.h>

    #define N 8

    int a[N] = {15,17,30,46,56,82,90,95};

    void print(int a[],int n)

    {

        int i;

        for (i = 0;i < n;i++)

            printf("%d",a[i]);

        printf("\n");

    }

intsearch(int a[],int k,int n)

    {

        int low = 0;

        int high = n-1;

        int mid;

        while (low <= high) {

            mid = (low + high) / 2;

            if (a[mid] == k) return mid;

            else if (a[mid] > k) high = mid -1;

            else low = mid + 1;

    }

        return -1;

    }

voidmain()

    {

        int k;

        clrscr();

        print(a,N);

        printf("Please input KEY :");scanf("%d",&k);

        printf("\n%d ",search(a,k,N));

        printf("\nPress any key toRETURN...");

        getche();

    }


二叉排序树

程序6_3.c实现二叉排序树的有关操作。第4行到第8行定义二叉排序树结点结构。第9行一维数组a存放用于构造二叉排序树的元素。

函数search按3.1所述思想查找与参数item匹配的结点,若找到这个结点,则返回该结点的地址,否则返回空。

第11行到第44行函数insert功能是将元素item插入二叉排序树中。若二叉排序树为空,则item作为根结点。若二叉排序树不空,则要根据item的值进行查找。

 

程序6_3.c

    #include <alloc.h>

    #define N 8

    typedef int ELEMTYPE;

    struct SortTree {

        ELEMTYPE elem;

        struct SortTree *left;

        struct SortTree *right;

    };

ELEMTYPEa[N] = {46,30,82,46,56,17,95,15};

    struct SortTree *root = NULL;

    void insert(ELEMTYPE item)

    {

        struct SortTree *ptr,*ptr1;

        if (root == NULL) {

        root=(structSortTree*)malloc(sizeof(structSortTree));

            root->elem = item;

            root->left = root->right =NULL;

        }

        else {

            ptr = root;

            while (ptr != NULL) {

                if (item < ptr->elem) {

                    ptr1 = ptr;

                    ptr = ptr->left;

                }

                else {

                    ptr1 = ptr;

                    ptr = ptr->right;

            }

            }

            if (item < ptr1->elem) {

            ptr=(structSortTree*)malloc(sizeof(structSortTree));

                ptr->left = ptr->right =NULL;

                ptr->elem = item;

            ptr1->left = ptr;

            }

            else {

               ptr=(structSortTree*)malloc(sizeof(structSortTree));

                ptr->left = ptr->right =NULL;

                ptr->elem = item;

                ptr1->right = ptr;

            }

        }

    }

    struct SortTree *search(struct SortTree*t,ELEMTYPE k)

    {

        struct SortTree *ptr = t;

        if (ptr == NULL)

            return ptr;

        while (ptr != NULL) {

            if (ptr->elem == k)

            return ptr;

            else if (k < ptr->elem)

                ptr = ptr->left;

            else ptr = ptr->right;

        }

        return NULL;

    }

    void main()

    {

        int i,k;

    struct SortTree *p;

        clrscr();

        for (i=0;i<N;i++)

            insert(a[i]);

    inorder(root);

        printf("\nPlease input K: ");

        scanf("%d",&k);

        p = search(root,k);

        if (p != NULL)

        printf("found! %d address is%p",p->elem,p);

        else

            printf("\nNot found %d",k);

    }

 

散列查找

       程序6_4.c实现线性探测解决冲突策略时散列查找与插入算法。第1行定义的常量M为散列表的大小,第2行定义的常量N为待散列的元素个数。第4行数组KEY存放待散列的元素。第5行定义散列表T。

       第6行到第9行的探测函数p的思想是:如果记录的基位置被占用,那么就在散列表中下移,,直到找到一个空位置。一旦到达表的底部,探测序列就回到表的开始处。       第10行到第13行的散列函数采用的是除留余数法。

第14行到第23行HashInsert函数将关键字k插入到散列表中。函数首先计算k的基位置,如果基位置被占用了,根据冲突解决策略到达下一个位置,如果这个位置也被占用了,那么就找下一个位置,依此类推。

第24行到第32行HashSearch从散列表中检索记录,过程与HashInsert函数类似。

第33行到第42行主函数main首先将散列表清空(第37行),然后将数组KEY中的元素插入到散列表中(第38行)。第39行和40行输出散列表中内容。第41行测试散列查找。

 

程序6_4.c

    #define M 11

    #define N 6

    #define EMPTY 0

    int KEY[N] ={9874,2009,1001,9537,3016,9875};

intT[M];

    int p(int k,int i)

    {

        returni;

    }

    int h(int k)

    {

    return k % M;

    }

    int HashInsert(int k)

    {

        inti,home;

        intpos = home = h(k);

        for(i = 1;T[pos] != EMPTY;i++) {

            pos= (home + p(k,i)) % M;

            if(T[pos] == k) return 0;

        }

        T[pos]= k;

    }

    int HashSearch(int k)

    {

        inti,home;

        intpos = home = h(k);

        for(i = 1;(T[pos] != k) && (T[pos] != 0);i++)

            pos= (home + p(k,i)) % M;

        if(T[pos] == k) return pos;

        elsereturn -1;

    }

    void main()

    {

        inti,item;

        clrscr();

        for(i = 0;i < M;i++) T[i] = 0;

        for(i=0;i<6;i++) HashInsert(KEY[i]);

        for(i=0;i<M;i++)

            printf("%d",T[i]);

    printf("\n%d%d",HashSearch(2009),T[HashSearch(2009)]);

    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值