【数据结构】链表取top数据(top 3)操作练习

从一个例子来回顾链表操作,学生数据包括学号(id)和学分(v),

相应的操作有添加学生数据,删除学生数据,修改学分,

一系列的操作后,求学分top 3的数据。

 

我们可以一开始就构造一个有序链表,来一个数据就插入到合适的位置,删除和修改时都找到相应的节点去操作,可以定义为双向链表来方便删除操作,这个思路比较清晰。但是如果修改和删除的次数较多,查找次数较多。

有些像表结构创建索引,复杂的索引可以很好的处理这个问题。

 

这里考虑以下处理方案:

1. 创建普通链表,在获取top的时候再进行遍历,比如获取top3数据,获取到top1的时候,可以对数据做个标记,方便获取到top2,再设置标记,获取到top3,完成后再回复标记。

struct stu{
    int id;
    int v;
    int tag;//
    stu* nt;
    stu* pre;

    inline bool isGreat(stu* o)
    {
        if (o == 0)
        {
            return true;
        }
        if (v > o->v)
        {
            return true;
        }
        else if(v == o->v && id < o->id)
        {
            return true;
        }
        return false;
    }

    inline void append(stu* s)
    {
        s->nt = nt;
        if (nt != 0)
        {
            nt->pre = s;
        }
        nt = s;
        s->pre = this;
    }

    inline void rmed()
    {
        pre->nt = nt;
        if (nt != 0)
        {
            nt->pre = pre;
        }
    }
};

//add del modify 
//get top3
stu stus;
int tn = 0;

stu alls[1000];

void add(stu* &hd, stu* s)
{
    s->nt = hd;
    if (hd != 0)
    {
        hd->pre = s;
    }
    hd = s;
}

void rm(stu* &hd, stu* s)
{
    if (hd == s)
    {
        hd = s->nt;
        s->nt->pre = hd;
    }
    else
    {
        stu* p = s->pre;
        p->nt = s->nt;
        if (s->nt != 0)
        {
            s->nt->pre = p;
        }
    }
}

void rmstu(int id)
{
    rm(stus.nt, &alls[id]);
}

void modify(int id, int v)
{
    alls[id].v = v;
}

int gettop()
{
    stu* top[3] = {0};
    int tn = 0;//record the number, maybe there is less than 3
    for (int i = 0; i < 3; i++)
    {
        stu* p = stus.nt;
        while (p != 0)
        {
            if (p->isGreat(top[i]) && p->tag == 0)
            {
                top[i] = p;
            }

            //
            p = p->nt;
        }

        
        if (top[i] != 0)
        {
            tn++;
            top[i]->tag = 1;//not selected in the next time
            
        }
    }

    printf("\n\ntop value is: ");
    //reset tag
    for (int i = 0; i < 3; i++)
    {
        if (top[i] != 0)
        {
            printf("%d, ", top[i]->v);
            top[i]->tag = 0;//
        }
    }

    return tn;
}

int data[][2] = {
    {1,3},{3,5},{2,2},{8,11},{7,5},{6,11},{5,3},{4,4},
    {10,5},{9,4},{11,6},{12,29},{13,3},{14,3},{15,22},{17,7},{16,5}
};



int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < 15; i++)
    {
        int id = data[i][0];
        int v = data[i][1];

        alls[id].id = id;
        alls[id].v = v;
        add(stus.nt, &alls[id]);
    }

    gettop();
    modify(4,44);
    modify(9,33);
    gettop();
    rmstu(9);
    gettop();

}

打印结果

top value is: 29, 22, 11,

top value is: 44, 33, 29,

top value is: 44, 29, 22,

 

2. 考虑建立部分排序top序列,当新的数据大于top序列的最小值时,替换进top序列,

需要考虑几种情况,修改的数据是否已经在top序列,删除的数据是否在top序列,每次操作都更新top序列,

在取top的时候,直接获取top序列即可。

这个方式需要考虑的情况较多。

构造一个链表来保存数据,链表的前面几个数据是top序列,用tmin标记最后一个top数据,其他的数据在tmin节点后,新来的数据如果大于tmin数据,就插入到top序列。如果删除的数据在top序列里,从tmin后面的序列中找一个最大的,补到top序列中。有数据修改时,可以理解为先删除再插入数据,这样来复用删除的代码。


#define TOPN 3


struct stu{
    int id;
    int v;
    int tag;//
    stu* nt;
    stu* pre;

    inline bool isGreat(stu* o)
    {
        if (o == 0)
        {
            return true;
        }
        if (v > o->v)
        {
            return true;
        }
        else if(v == o->v && id < o->id)
        {
            return true;
        }
        return false;
    }

    inline void append(stu* s)
    {
        s->nt = nt;
        if (nt != 0)
        {
            nt->pre = s;
        }
        nt = s;
        s->pre = this;
    }

    inline void rmed()
    {
        pre->nt = nt;
        if (nt != 0)
        {
            nt->pre = pre;
        }
    }
};


int data[][2] = {
    {1,3},{3,5},{2,2},{8,11},{7,5},{6,11},{5,3},{4,4},
    {10,5},{9,4},{11,6},{12,29},{13,3},{14,3},{15,22},{17,7},{16,5}
};





struct ts{
    int tn;
    stu hd;
    stu* tmin;

    void pt()
    {
        stu* p = hd.nt;
        while (p != 0)
        {
            printf("%d(%d), ", p->id, p->v);
            p = p->nt;
        }
    }
    stu* getmax()
    {
        stu* m = 0;
        stu* p = tmin->nt;
        while (p != 0)
        {
            if (p->isGreat(m))
            {
                m = p;
            }
            p = p->nt;
        }
        return m;
    }

    bool isin(stu* s)
    {
        stu* p = hd.nt;
        for (int i = 0; i < tn; i++)
        {
            if (p == s)
            {
                return true;
            }
            p = p->nt;
        }
        return false;
    }

    void update(stu* s)
    {
        if (isin(s))
        {
            rm(s);
            add(s);
        }
        else if (s->isGreat(tmin))
        {
            s->rmed();
            add(s);
        }

    }

    void rm(stu* s)
    {
        if (isin(s))
        {
            stu* m = getmax();
            s->rmed();
            tn--;

            if (m != 0)
            {
                m->rmed();
                add(m);
            }
            getmin();
        }
        else
        {
            s->rmed();
        }
    }
    stu* getmin()
    {
        stu* p = hd.nt;
        for (int i = 0; i < tn-1; i++)
        {
            p = p->nt;
        }
        tmin = p;
        return tmin;
    }

    void add(stu* s)
    {
        if (tn < TOPN)
        {
            addsort(s);
            tn++;
            getmin();
        }
        else if (s->isGreat(tmin))
        {
            addsort(s);
            getmin();
        }
        else
        {
            tmin->append(s);
        }
    }


    void addsort(stu* s)
    {
        stu* p = &hd;

        while (p->nt != 0)
        {
            if (s->isGreat(p->nt))
            {
                break;
            }
            p = p->nt;
        }
        p->append(s);
    }
};

ts tlist;
stu sdat[1000];

int _tmain(int argc, _TCHAR* argv[])
{

    
    for (int i = 0; i < 15; i++)
    {
        int id = data[i][0];
        int v = data[i][1];
        sdat[id].id = id;
        sdat[id].v = v;
        tlist.add(&sdat[id]);
    }

    for (int i = 0; i < 15; i++)
    {
        int id = data[i][0];
        int v = data[i][1];

    //    sdat[id].id = id;
    //    sdat[id].v = v;
        if (id == 15)
        {
            sdat[id].v = 9;
            printf("\nupdate:");
            tlist.update(&sdat[id]);
        }
        else if (id == 6)
        {
            sdat[id].v = 39;
            printf("\nupdate:");
            tlist.update(&sdat[id]);
        }
        else if (id == 4)
        {
            sdat[id].v = 29;
            printf("\nupdate:");
            tlist.update(&sdat[id]);
        }
        else
        {
            tlist.rm(&sdat[id]);
        }
        
        printf("\n\n id=%d :", id);
        tlist.pt();
    }


    return 0;
}


再修改下


struct ts{
	int tn;
	stu hd;
	stu* tmin;

	inline void init()
	{
		tn = 0;
		hd.nt = 0;
		tmin = 0;
	}

	void pt()
	{
		stu* p = hd.nt;
		while (p != 0)
		{
			printf("%d(%d), ", p->id, p->v);
			p = p->nt;
		}
	}
	inline private stu* getmax()
	{
		stu* m = 0;
		stu* p = tmin->nt;
		while (p != 0)
		{
			if (p->isGreat(m))
			{
				m = p;
			}
			p = p->nt;
		}
		return m;
	}

	bool isin(stu* s)
	{
		stu* p = hd.nt;
		for (int i = 0; i < tn; i++)
		{
			if (p == s)
			{
				return true;
			}
			p = p->nt;
		}
		return false;
	}

	inline void update(stu* s)
	{
		//the data may be lower, so need to check if data in Top list changed
		if (isin(s))
		{
			rmIn(s);
			add(s);
		}
		else if (s->isGreat(tmin))
		{
			s->rmed();
			add(s);
		}
	}


	//remove stu in Top list, so it need to find a max value
	//in the rest l
	inline private void rmIn(stu* s)
	{
		stu* m = getmax();
		s->rmed();
		tn--;

		if (m != 0)
		{
			m->rmed();
			add(m);
		}
		getmin();
	}

	void rm(stu* s)
	{
		if (s->isGreat(tmin))
		{
			rmIn(s);
		}
		else
		{
			s->rmed();
		}
		/*
		if (s->isGreat(tmin))
		{
			s->rmed();
			tn--;
			stu* m = getmax();
			if (m != 0)
			{
				m->rmed();
				add(m);
			}
		}
		else if (s == tmin)
		{
			stu* m = getmax();
			s->rmed();
			tn--;
			
			if (m != 0)
			{
				m->rmed();
				add(m);
			}
			getmin();
		}
		else
		{
			s->rmed();
		}
*/
	}
	inline private stu* getmin()
	{
		stu* p = hd.nt;
		for (int i = 0; i < tn - 1; i++)
		{
			p = p->nt;
		}
		tmin = p;
		return tmin;
	}

	inline void add(stu* s)
	{
		if (tn < TOPN)
		{
			addsort(s);
			tn++;
			getmin();
		}
		else if (s->isGreat(tmin))
		{
			addsort(s);
			getmin();
		}
		else
		{
			tmin->append(s);
		}
	}


	inline private void addsort(stu* s)
	{
		stu* p = &hd;

		while (p->nt != 0)
		{
			if (s->isGreat(p->nt))
			{
				break;
			}
			p = p->nt;
		}
		p->append(s);
	}
};

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值