Страница 1 из 1

Слияние двух кольцевых двунаправленных списков на C++ 3. 1

Добавлено: 31 май 2005, 19:29
Lei fang
Всем привет!!!

Помогите разобраться с слиянием двух кольцевых двунаправленных списков. Близится сессия, надо успеть.

Есть у меня такой исходник:

Код: Выделить всё

#include<conio.h>
#include<dos.h>
#include<stdio.h>

struct list
{
	int data;
	list *next;
	list *prev;
}; list *cur=0;

struct list2
{
	int data2;
	list2 *next;
	list2 *prev;
}; list2 *cur2=0;

Unitor()
{
	list *tmp=cur2->prev;
	cur->prev->next=cur2;
	cur2->prev->next=cur;
	tmp=cur2->prev;
	cur2->prev=cur->prev;
	cur->prev=tmp;
	delete tmp;
        return 0;
}


//Функция добавления элемента в список
AddAfterCur(int elem)
{
	list *tmp;
	tmp=new list;
	if (tmp==0){printf("\nНевозможно выделить память");}

	printf("\n\nВведите число   ");
	scanf("%i",&elem); printf("\n%i",elem);

	tmp->data=elem;
	tmp->next=cur->next;
	tmp->prev=cur->prev;

	if(cur==0)	//Добавление первого элемента
	{
		cur->next=tmp;
		cur=tmp;
		cur->prev=cur;
		cur->next=cur;
	}
	if(cur!=0)		//Добавление элементов
	{
		cur->next=tmp;
		cur->next->prev=cur;
		cur=tmp;
		cur->next->prev=cur;
	}
	return 0;
}


//Функция удаления текущего элемента
DeleteCurrent()
{
	if(cur==NULL)
	{
		printf("\n\nСписок пуст");
		getch();
		return 0;
	}

	list *tmp=cur->prev;
	cur->next->prev=tmp;
	cur->prev->next=cur->next;
	delete cur;
	cur=tmp;
	return 0;
}


//Функция выбора текущего элемента
CurMove(char key)
{
	if(cur==NULL)
	{
		printf("\n\nСписок пуст");
		getch();
		return 0;
	}

	printf("\n\nКуда Вы хотите переместить курсор?\n\n");
	printf("1 - Вперед\n");
	printf("2 - Назад\n\n");
	printf("Введите номер команды  ");

	key=getch();

	if(key=='1')	//Движение текущего элемента вперед
	{
		cur=cur->next;
	}

	if(key=='2')	//Движение текущего элемента назад
	{
		cur=cur->prev;
	}
	return 0;
}




AddAfterCur2(int elem)
{
	list2 *tmp2;
	tmp2=new list2;
	if (tmp2==0){printf("\nНевозможно выделить память");}

	printf("\n\nВведите число   ");
	scanf("%i",&elem); printf("\n%i",elem);

	tmp2->data2=elem;
	tmp2->next=cur2->next;
	tmp2->prev=cur2->prev;

	if(cur2==0)	//Добавление первого элемента
	{
		cur2->next=tmp2;
		cur2=tmp2;
		cur2->prev=cur2;
		cur2->next=cur2;
	}
	if(cur2!=0)		//Добавление элементов
	{
		cur2->next=tmp2;
		cur2->next->prev=cur2;
		cur2=tmp2;
		cur2->next->prev=cur2;
	}
	return 0;
}


//Функция удаления текущего элемента
DeleteCurrent2()
{
	if(cur2==0)
	{
		printf("\n\nСписок пуст");
		getch();
		return 0;
	}

	list2 *tmp2=cur2->prev;
	cur2->next->prev=tmp2;
	cur2->prev->next=cur2->next;
	delete cur2;
	cur2=tmp2;
	return 0;
}


//Функция выбора текущего элемента
CurMove2(char key)
{
	if(cur2==0)
	{
		printf("\n\nСписок пуст");
		getch();
		return 0;
	}

	printf("\n\nКуда Вы хотите переместить курсор?\n\n");
	printf("1 - Вперед\n");
	printf("2 - Назад\n\n");
	printf("Введите номер команды  ");

	key=getch();

	if(key=='1')	//Движение текущего элемента вперед
	{
		cur2=cur2->next;
	}

	if(key=='2')	//Движение текущего элемента назад
	{
		cur2=cur2->prev;
	}
	return 0;
}


//Начало главной функции
main()
{
	int elem, flag=0;
	char key;

	do
	{
		if(flag==0)
		{
			clrscr();
			list *tmp=cur;
			printf("                              Первый список");
			printf("\n\nТекущий элемент равен   %i\n",*cur);	//Вывод на экран текущего элемента
			do
			{
				if(cur==NULL)
				{
					printf("\nСписок пуст");
					break;
				}
				if(cur!=0)
				{
					cur=cur->next;
					printf(" %i ",*cur);	//Вывод всех элементов списка
				}
			} while(cur!=tmp);

			printf("\n1 - Добавить элемент после текущего\n");
			printf("2 - Перейти к ...\n");
			printf("3 - Удалить текущий элемент\n");
			printf("Стрелка вправо - Перейти ко второму списку");
			printf("\n\nВведите номер команды	");

			key=getch();
			if(key=='1'){AddAfterCur(elem);}
			if(key=='2'){CurMove(key);}
			if(key=='3'){DeleteCurrent();}
			if(key==77){flag=1;}
		}

		if(flag==1)
		{
			clrscr();
			list2 *tmp2=cur2;
			printf("                              Второй список");
			printf("\n\nТекущий элемент равен   %i\n",*cur2);	//Вывод на экран текущего элемента
			do
			{
				if(cur2==0)
				{
					printf("\nСписок пуст");
					break;
				}
				if(cur2!=0)
				{
					cur2=cur2->next;
					printf(" %i ",*cur2);	//Вывод всех элементов списка
				}
			} while(cur2!=tmp2);
			printf("\n1 - Добавить элемент после текущего\n");
			printf("2 - Перейти к ...\n");
			printf("3 - Удалить текущий элемент\n");
			printf("Стрелка влево - Перейти к первому списку");
			printf("\n\nВведите номер команды	");

			key=getch();
			if(key=='1'){AddAfterCur2(elem);}
			if(key=='2'){CurMove2(key);}
			if(key=='3'){DeleteCurrent2();}
			if(key==75){flag=0;}
		}

		if(key=='u'){Unitor();}
	} while(key!=27);
	return 0;
}
Функция Unitor должна заниматься слиянием списков, однако она не работает (выдает ошибки о приведении типов, а когда я делаю явное преобразование типов, на экран выводится какой-то мусор).
Этот исходник без явного приведения типов. Если кто-нибудь знает в чем моя ошибка, то помогите мне, пожалуйста...
Зарание спасибо

Добавлено: 01 июн 2005, 13:34
Kolinus
естественно ошибки
у тебя типа лист и лист2 не наследуют друг от друга то есть они абсолютно независимы.
возникает вопрос зачем тебе 2 типа если они у тебя одинаковы по своим членам ????
Плюс функция написана непонятно
list *tmp=cur2->prev;
cur->prev->next=cur2;
cur2->prev->next=cur;
tmp=cur2->prev;
cur2->prev=cur->prev;
cur->prev=tmp;
delete tmp;
return 0;
ты объявляешь тмп и инициализируешь, но до следующей операции присваивания ты ее НЕ ИСПОЛЬЗУЕШЬ
к тому же если ты сливаешь списки как ты можешь удалять ХОТЬ ОДИН ЭЛЕМЕНТ - ты же их СЛИВАЕШЬ
ты бы с ручкой и бумагой сел бы чтоли да нарисовал что куда переставит

Добавлено: 01 июн 2005, 13:37
Kolinus
навскидку код такой
tmp=cur->prev
tmp2=cur2->next
cur2->next=cur
cur->prev=cur2
tmp2->prev=tmp
tmp->next=tmp2

Щиа-а-ха

Добавлено: 01 июн 2005, 14:46
Lei fang
Спасибо тебе, Kolinus, теперь все ясно. Эх... все было так просто...
Хочу оставить твой правильный вариант написания функции слияния списков, если она когда-нибудь кому-нибудь понадобится.
Я так и оставил 2 типа для того, чтобы... Да просто легче было оставить их и задать явное преобразование типов.

Код: Выделить всё

Unitor()
{
	/*Обратите внимание! Так не надо программировать!*/

	/*list *tmp=(list *)cur2->prev;
	cur->prev->next=(list*)cur2;
	cur2->prev->next=(list2*)cur;
	tmp=(list*)cur2->prev;
	cur2->prev=(list2*)cur->prev;
	cur->prev=tmp;
	delete tmp;
	return 0;*/


	/*Так надо*/

	list *tmp; list *tmp2;
	tmp=cur->prev;
	tmp2=(list*)cur2->next;
	cur2->next=(list2*)cur;
	cur->prev=(list*)cur2;
	tmp2->prev=tmp;
	tmp->next=tmp2;
	return 0;
}
Еще раз хочу поблагодарить тебя, Kolinus, теперь мне осталось только сгенерировать подмножества и все!!!

Добавлено: 01 июн 2005, 16:52
dagrs
Слияние кольцевых объектов - по какому принципу?
По способу построения, т.е. от текущих указателей, разрывающих кольцо?
Тогда:

Код: Выделить всё

void Unitor() 
{ 
    if( !cur2 ) return; 
    if( !cur  ) { cur = (list *)(cur2); cur2 = NULL; return; } 

    list *temp = cur->next; 
    cur ->next = (list  *)(cur2->next); 
    cur2->next = (list2 *)temp; 

    temp = cur->next->prev; 
    cur ->next->prev = (list  *)(cur2->next->prev); 
    cur2->next->prev = (list2 *)temp; 
}

Добавлено: 01 июн 2005, 17:44
Lei fang
Великолепно!!! Эта функция еще и возвращает списки в исходное состояние! Класс! Спасибо тебе, Dagrs!

Добавлено: 01 июн 2005, 18:00
Lei fang
Ой... Что-то функция удаления как-то странно удаляет элемент, остающийся в списке последним (единственным)...

Добавлено: 02 июн 2005, 13:03
Kolinus
Ничего странного нет
как ты написал так она и удаляет.
Фишка в том что оператор delete лишь освобождает память, не обнуляя указатель на данную память.
Получается что у последнего элемента все ссылки идут на него самого и посему при удалении еготы освобождаешь память,
тмп у тебя указывает на мусор и потом ты кар перемтавляешь тоже в мусор.
Для разруливания ситуации попробуй проверять ссылки с элемента и если они все одинаковы, то удалять элемент и обнулять на него указатель

Добавлено: 02 июн 2005, 15:34
Lei fang
Kolinus, спасибо за совет. Посидел я немного с ручкой, и получил вот такой код:

Код: Выделить всё

DeleteCurrent()
{
	if(cur==NULL)
	{
		printf("\n\n‘ЇЁб®Є Їгбв");
		getch();
		return 0;
	}

	if(cur->prev==cur || cur->next==cur)
	{
		delete cur; cur=0; return 0;
	}
	else
	{
		list *tmp=cur->prev;
		cur->next->prev=tmp;
		cur->prev->next=cur->next;
		delete cur;
		cur=tmp;
		return 0;
	}
}
Теперь без всякого мусора удаляется единственный элемент. Думаю его можно оптимизировать...