邻接链表线性时间去重 C代码 算法导论 22.1-4

这里利用直接寻址法去重,遍历链表,如果对应数组位置值为0,则修正为1,如果对应数组为1,则删除该节点。(数组初始化为0)

链表的一些操作都简单的实现了一下。

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

struct Node{
    int key;
    Node *next;
};

struct List{
    Node *head;
};
typedef struct Node Node;
typedef struct List List;

void Init(List *list){
    list->head = NULL;
}
Node *List_Search(List *list, int k){
    Node *temp = list->head;
    while (temp&&temp->key != k)
        temp = temp->next;
    return temp;
}

void Insert(List *list, int key){
    Node *p = (Node*)malloc(sizeof (Node));
    p->key = key;
    p->next = list->head;
    list->head = p;
}

Node *Delete_Byptr(List *list,Node *prev,Node *wanted){
    if (prev){
        prev->next = wanted->next;
        free(wanted);
        return prev->next;
    }
    else {
        list->head = wanted->next;
        free(wanted);
        return list->head;
    }
}

void Delete_Bykey(List *list, int key){
    Node *temp = list->head;
    Node *prev = 0;
    while (temp&&temp->key != key){
        prev = temp;
        temp = temp->next;
    }
    if (temp){
        prev->next = temp->next;
        free(temp);
    }
}

//合并两个数组
List *Union(List *list1, List *list2){
    if (!list1->head)
        return list2;
    Node *temp = list1->head;
    while (temp->next)
        temp = temp->next;
    temp->next = list2->head;
    return list1;
}

void Print_List(List *list){
    Node *temp = list->head;
    while (temp){
        printf("%d ", temp->key);
        temp = temp->next;
    }
}

typedef Node Vnode;

//这里假设key为0到V-1,表示的是第(key+1)个节点
void Unique(List *Adj, int V){
    int *p = (int *) calloc(V,sizeof(int));
    for (int i = 0; i < V; ++i){
        Vnode *temp = Adj[i].head;
        Vnode *prev = 0;
        while (temp){
            if (p[temp->key] == 1 || temp->key == i)
                temp=Delete_Byptr(&Adj[i], prev, temp);
            else {
                p[temp->key] = 1;
                prev = temp;
            temp = temp->next;
            }
        }
        //数组元素都置为0
        temp = Adj[i].head;
        while (temp){
            p[temp->key] = 0;
            temp = temp->next;
        }
    }
    free(p);
}

void Print(List *Adj, int V){
    for (int i = 0; i < V; ++i){
        Vnode *temp = Adj[i].head;
        printf("Node%d ", i);
        while (temp){
            printf("%d ", temp->key);
            temp = temp->next;
        }
        printf("\n");
    }
}

int main(){
    List list1,list2,list3;
    Init(&list1); Init(&list2); Init(&list3);
    Insert(&list1, 0);
    Insert(&list1, 1); Insert(&list1, 1); Insert(&list1, 1);
    Insert(&list1, 2); Insert(&list1, 2);
    Insert(&list2, 2); Insert(&list2, 2);
    Insert(&list3, 1); Insert(&list3, 1);
    List Adj[3] = { list1,list2,list3 };
    Print(Adj, 3);
    Unique(Adj, 3);
    Print(Adj, 3);
}
时间: 2024-08-03 23:28:55

邻接链表线性时间去重 C代码 算法导论 22.1-4的相关文章

快速排序实现代码 算法导论7.1 7.2 7.4

快速排序通常是实际排序中应用最好的选择,因为平均性能很好,且是原址排序,不稳定. 书上的大部分内容在分析其运行时间,感觉看一下就好了(还是蛮喜欢数学的,可是...) #include <iostream> #include <algorithm> #include <random> using namespace std; //实际应用比较多,原址排序 typedef int index; index Partition(int *a, index p, index r

算法导论22.4拓扑排序 练习总结 (转载)

22.4-1 给出算法 TOPOLOGICAL-SORT 运行于图 22-8 上时所生成的结点次序.这里的所有假设和练习 22.3-2 一样. ANSWER:   22.4-2 请给出一个线性时间的算法,算法的输入为一个有向无环图 G = (V, E) 以及两个结点 s 和 t,算法的输出是从结点 s 到结点 t 之间的简单路径的数量.例如,对于图 22-8 所示的有向无环图,从结点 p 到结点 v 一共有 4 条简单路径,分别是 pov.poryv.posryv 和 psryv.(本题仅要求计

算法导论22.3深度优先搜索 练习总结 (转载)

22.3-1 画一个 3*3 的网格,行和列的抬头分别标记为白色.灰色和黑色,对于每个表单元 (i, j),请指出对有向图进行深度优先搜索的过程中,是否可能存在一条边,链接一个颜色为 i 的结点和一个颜色为 j 的结点.对于每种可能的边,指明该种边的类型.另外,请针对无向图的深度优先搜索再制作一张这样的网格. ANSWER:   22.3-2 给出深度优先搜索算法在图 22-6 上的运行过程.假定深度优先搜索算法的第 5~7 行的 for 循环是以字母表顺序依次处理每个结点,假定每条邻接链表皆以

『算法设计_伪代码』线性时间排序及排序算法对比

一.计数排序 二.基数排序 三.桶排序 四.对比不同排序方法 原文地址:https://www.cnblogs.com/hellcat/p/9255591.html

双端队列C实现代码 算法导论10.1-5 10.1-6 10.1-7

数组实现双端队列的时候注意区别判断上溢和下溢. 用两个栈实现队列,就相当于把两个栈底靠在一起(背靠背),一个栈用来出队列,一个栈用来进队列.这个队列的操作时间大部分时候是常数时间,除了出列的栈为空,需要把进列的栈全部转移过去,再出列.Back()操作和Pop()操作类似,也是这样. 而两个队列实现栈,队列轮流充当入栈和出栈的角色,而什么时候会改变角色呢,就是Pop()操作.Pop()操作先把一个队列中的所有元素全部出列并加入另外一个空队列中去,然后再出列(第二个队列). 实现代码为C #incl

Young氏矩阵类C++实现代码 算法导论6.3

个人总结: 1.int **p和 int a[M][N]之间的区别: 1) int **指向指针的指针:而后者的类型是数组名,类型为 int (*)[N],即指向的是整个一行. 2) (a+1) 表示地址增加M*sizeof(int),需要注意的一点是a[i]是第i行开头的地址,&a和a的值是一样的.数组名是附带大小属性的,而指针是一个存储了地址的变量.特意去看了一下声明数组的汇编代码,其中一条指令是mov %gs:0x14,%eax  (数组大小20即0x14),最后也貌似也会检查一下数组是否

算法导论22章基本的图算法 思考题总结 (转载)

22-1 (以广度优先搜索来对图的边进行分类)深度优先搜索将图中的边分类为树边.后向边.前向边和横向边.广度优先搜索也可以用来进行这种分类.具体来说,广度优先搜索将从源结点可以到达的边划分为同样的4种类型. a.证明在对无向图进行的广度优先搜索中,下面的性质成立: 1.不存在后向边,也不存在前向边. 2.对于每条树边(u, v),我们有v.d = u.d + 1. 3.对于每条横向边(u, v),我么有v.d = u.d 或 v.d = u.d + 1. b.证明在对有向图进行广度优先搜索时,下

【算法导论-学习笔记】以线性时间增长的排序——计数排序

计数排序是一种能够达到运行时间能够线性时间θ(n)的排序算法.在排序算法里算是最快的算法之一,当然,他有很强烈的前提.下面开始介绍一下技术排序(Counting Sort). 算法思想 计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,此处k为某个整数.这样可以用一个数组C[0..k]来记录待排序数组里元素的数量.当k=O(n)时,计数排序的运行时间为θ(n). 注:关于C[0..k],用键值对描述的话,待排序元素是键,相同元素的个数是值.例:待排序数组<2,3 , 6,4 , 1 ,

《算法导论》读书笔记--第三章 函数的增长

好长时间了,继续算法导论. 当输入规模足够大时,并不计算精确的运行时间,倍增常量和低阶项被舍去.我们要研究的是算法的渐近效率,即在输入规模无限量时,在极限中,算法的运行时间如何随着输入规模的变大而增加.通常,渐近的更有效的某个算法除对很小得到输入外都是最好的选择. 3.1渐近符号 用渐近符号来刻画算法的运行时间.