比较顺序表和链表
- 顺序表便于理解,容易实现;链表不需要事先分配存储空间,每次插入和删除结点时动态的开辟和释放空间,便于存储空间的管理;
- 顺序表事先开辟和随后增加的空间是一块存储位置相邻的连续存储空间,当存储的数据量很大时,内存可能无法找到一块足够大的连续空间予以分配;链表的结点之间是通过指针连接,在内存中可以分散存储,可提高存储空间利用率。
- 顺序表可以通过下标快速访问某个结点;链表则需要从头遍历依次查找;
- 顺序表进行插入或删除操作时,平均需要移动半个表的元素,相当费时;链表进行插入或删除操作时,只需修改相关结点的指针域,方便又省时;
- 由于链表的每个结点都带有指针域,从存储密度来讲,是特别不经济的;顺序表中只存了结点数据,若不考虑空闲区,存储密度为1,链表的存储密度小于1。
存储密度=结点数据本身所占的存储量/结点结构所占的存储总量
顺序表适用于尾插尾删较多的场景;链表适用于头插或中间插入较多的场景。
从尾到头打印单链表
递归方法的思想就是:先打印出cur结点之后的链表,再打印cur。
void PrintEndToStartR(pList plist)
{
pNode cur = plist;
if (plist == NULL)
return;
if (cur->_next != NULL)
{
PrintEndToStartR(cur->_next);
}
printf("%d ", cur->_data);
}
非递归方法:借用栈,先把单链表的节点全部压入进栈,再依次取栈顶节点即可。
void PrintEndToStart()
{
stack<DataType> s;
Node *cur = _head;
while (cur)
{
s.push(cur->_data);
cur = cur->_next;
}
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
cout << endl;
}
删除一个无头单链表的非尾节点
这实际是一种偷梁换柱的思想:把要删除的结点后一个结点的数据赋给删除结点,删除要删除结点后一个结点。是不是有点绕?看图吧!
void EraseWithoutHead(pNode pos)
{
assert(pos);
pNode del = NULL;
if (pos->_next)
{
del = pos->_next;
pos->_data = del->_data;
pos->_next = del->_next;
free(del);
}
}
在无头单链表的一个节点前插入一个节点
思想:新建一个要插入数据的结点,把pos结点与新结点中的数据交换,再把新结点插到pos结点后。
void InsertWitnoutHead(pNode pos, int d)
{
assert(pos);
pNode newNode = (pNode)malloc(sizeof(pNode));
newNode->_data = pos->_data;
pos->_data = d;
newNode->_next = pos->_next;
pos->_next = newNode;
}
单链表实现约瑟夫环
约瑟夫环问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
注意释放结点之前要先把释放的那个结点之前的结点和之后的结点连接起来!
pNode JosephCycle(pList *pplist, int num)
{
assert(pplist);
pNode cur = *pplist;
pNode del = *pplist;
int i = 0;
while (cur->_next != cur)
{
for (i = 0; i < num - 1; i++)
{
cur = cur->_next;
}
printf("%d ", cur->_data);
del = cur->_next;
cur->_data = del->_data;
cur->_next = del->_next;
free(del);
del = NULL;
}
return cur;
}
逆置/反转单链表
void ReverseList(pList *pplist)
{
pNode prev = *pplist;
pNode cur = prev->_next;
pNode tmp = NULL;
if (*pplist == NULL || (*pplist)->_next == NULL)
return;
while (cur)
{
tmp = cur->_next;
cur->_next = prev;
prev = cur;
cur = tmp;
}
(*pplist)->_next = NULL;
*pplist = prev;
}
单链表排序(冒泡排序)
直接运用冒泡排序的思想。
void BubbleSortList(pList *pplist, size_t length)
{
pNode cur = *pplist;
pNode next = NULL;
DataType tmp